关于大模型应用开发的几点记录

大模型应用开发相关的坑,多半出在边界条件上。

这次做大模型应用开发,从简单 API 到复杂 Agent,。

基础 API 调用

OpenAI API

import openai

# 初始化客户端
client = openai.OpenAI(api_key="your-api-key")

# 基础调用
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Hello, how are you?"}
    ]
)

print(response.choices[0].message.content)

流式响应

def stream_chat(messages):
    stream = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        stream=True
    )
    
    for chunk in stream:
        if chunk.choices[0].delta.content:
            yield chunk.choices[0].delta.content

# 使用
for content in stream_chat([
    {"role": "user", "content": "Tell me a story"}
]):
    print(content, end="", flush=True)

函数调用

import json

# 定义函数
def get_weather(location, unit="celsius"):
    """获取天气信息"""
    # 实际调用天气 API
    return {
        "location": location,
        "temperature": 25,
        "condition": "sunny",
        "unit": unit
    }

# 函数描述
functions = [
    {
        "name": "get_weather",
        "description": "获取指定地点的天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市名称"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位"
                }
            },
            "required": ["location"]
        }
    }
]

# 使用函数调用
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "user", "content": "北京现在的天气怎么样?"}
    ],
    functions=functions,
    function_call="auto"
)

message = response.choices[0].message

if message.function_call:
    function_name = message.function_call.name
    function_args = json.loads(message.function_call.arguments)
    
    # 执行函数
    if function_name == "get_weather":
        result = get_weather(**function_args)
        
        # 将结果返回给模型
        response = client.chat.completions.create(
            model="gpt-4",
            messages=[
                {"role": "user", "content": "北京现在的天气怎么样?"},
                message,
                {"role": "function", "name": function_name, "content": json.dumps(result)}
            ]
        )
        
        print(response.choices[0].message.content)

提示词工程

结构化提示

def structured_prompt(prompt_type, **kwargs):
    prompts = {
        "qa": f"""
Question: {kwargs['question']}
Context: {kwargs.get('context', '')}

Answer the question based on the context. If the answer is not in the context, say "I don't know".
""",
        "summarize": f"""
Text: {kwargs['text']}

Summarize the above text in 2-3 sentences.
""",
        "extract": f"""
Text: {kwargs['text']}
Information to extract: {kwargs['target']}

Extract the following information from the text.
"""
    }
    
    return prompts.get(prompt_type, "")

# 使用
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": structured_prompt("qa", 
        question="What is the capital of France?",
        context="Paris is the capital and largest city of France."
    )}
]

链式提示

def chain_of_thought(prompt):
    messages = [
        {
            "role": "system",
            "content": """You are a helpful assistant. Think step by step:
1. Understand the problem
2. Identify the relevant information
3. Reason through the problem
4. Provide the final answer
"""
        },
        {"role": "user", "content": prompt}
    ]
    
    return client.chat.completions.create(
        model="gpt-4",
        messages=messages
    ).choices[0].message.content

# 使用
result = chain_of_thought(
    "A store sells apples for $2 each and oranges for $1.5 each. "
    "If someone buys 3 apples and 4 oranges, how much do they spend?"
)
print(result)

少样本学习

def few_shot_prompt(examples, query):
    prompt = "Here are some examples:\n\n"
    
    for example in examples:
        prompt += f"Input: {example['input']}\n"
        prompt += f"Output: {example['output']}\n\n"
    
    prompt += f"Input: {query}\n"
    prompt += "Output:"
    
    return prompt

# 使用
examples = [
    {"input": "cat", "output": "meow"},
    {"input": "dog", "output": "bark"},
    {"input": "bird", "output": "chirp"}
]

prompt = few_shot_prompt(examples, "cow")

response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "user", "content": prompt}
    ]
)

print(response.choices[0].message.content)

RAG(检索增强生成)

基础 RAG

from typing import List, Dict
import openai

class RAGSystem:
    def __init__(self, documents: List[str]):
        self.documents = documents
        self.embeddings = self._create_embeddings()
    
    def _create_embeddings(self):
        # 为所有文档创建嵌入
        embeddings = []
        for doc in self.documents:
            response = openai.Embedding.create(
                model="text-embedding-ada-002",
                input=doc
            )
            embeddings.append(response['data'][0]['embedding'])
        return embeddings
    
    def search(self, query: str, top_k: int = 3) -> List[Dict[str, str]]:
        # 为查询创建嵌入
        query_response = openai.Embedding.create(
            model="text-embedding-ada-002",
            input=query
        )
        query_embedding = query_response['data'][0]['embedding']
        
        # 计算相似度
        similarities = []
        for i, doc_embedding in enumerate(self.embeddings):
            similarity = self._cosine_similarity(query_embedding, doc_embedding)
            similarities.append({
                'document': self.documents[i],
                'similarity': similarity
            })
        
        # 返回最相似的文档
        similarities.sort(key=lambda x: x['similarity'], reverse=True)
        return similarities[:top_k]
    
    def _cosine_similarity(self, a, b):
        # 计算余弦相似度
        dot_product = sum(x * y for x, y in zip(a, b))
        magnitude_a = sum(x ** 2 for x in a) ** 0.5
        magnitude_b = sum(y ** 2 for y in b) ** 0.5
        return dot_product / (magnitude_a * magnitude_b)
    
    def generate_answer(self, query: str) -> str:
        # 检索相关文档
        context_docs = self.search(query)
        context = "\n".join([doc['document'] for doc in context_docs])
        
        # 生成回答
        messages = [
            {
                "role": "system",
                "content": "You are a helpful assistant. Answer the question based on the provided context."
            },
            {
                "role": "user",
                "content": f"""Context: {context}

Question: {query}

Answer:"""
            }
        ]
        
        response = client.chat.completions.create(
            model="gpt-4",
            messages=messages
        )
        
        return response.choices[0].message.content

# 使用
documents = [
    "Python is a high-level programming language.",
    "JavaScript is used for web development.",
    "Python is widely used in data science and machine learning.",
    "JavaScript can run in both browsers and servers."
]

rag = RAGSystem(documents)
answer = rag.generate_answer("What is Python used for?")
print(answer)

向量数据库

import chromadb
from chromadb.config import Settings

class VectorRAGSystem:
    def __init__(self):
        self.client = chromadb.Client(Settings(
            chroma_db_impl="duckdb+parquet",
            persist_directory="./chroma_db"
        ))
        self.collection = self.client.get_or_create_collection("documents")
    
    def add_documents(self, documents: List[str], metadatas: List[Dict] = None):
        # 为文档创建嵌入并存储
        embeddings = []
        for doc in documents:
            response = openai.Embedding.create(
                model="text-embedding-ada-002",
                input=doc
            )
            embeddings.append(response['data'][0]['embedding'])
        
        # 添加到向量数据库
        self.collection.add(
            documents=documents,
            embeddings=embeddings,
            metadatas=metadatas or [{}] * len(documents),
            ids=[f"doc_{i}" for i in range(len(documents))]
        )
    
    def search(self, query: str, n_results: int = 3) -> List[Dict]:
        # 为查询创建嵌入
        query_response = openai.Embedding.create(
            model="text-embedding-ada-002",
            input=query
        )
        query_embedding = query_response['data'][0]['embedding']
        
        # 搜索向量数据库
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=n_results
        )
        
        return results['documents'][0]
    
    def generate_answer(self, query: str) -> str:
        # 检索相关文档
        context_docs = self.search(query)
        context = "\n".join(context_docs)
        
        # 生成回答
        messages = [
            {
                "role": "system",
                "content": "You are a helpful assistant. Answer the question based on the provided context."
            },
            {
                "role": "user",
                "content": f"""Context: {context}

Question: {query}

Answer:"""
            }
        ]
        
        response = client.chat.completions.create(
            model="gpt-4",
            messages=messages
        )
        
        return response.choices[0].message.content

# 使用
rag = VectorRAGSystem()

# 添加文档
documents = [
    {"text": "Python is a high-level programming language.", "source": "doc1"},
    {"text": "JavaScript is used for web development.", "source": "doc2"},
    {"text": "Python is widely used in data science.", "source": "doc3"}
]

rag.add_documents(
    [doc["text"] for doc in documents],
    [{"source": doc["source"]} for doc in documents]
)

# 生成回答
answer = rag.generate_answer("What is Python used for?")
print(answer)

Agent 开发

基础 Agent

class Agent:
    def __init__(self, name: str, tools: List[callable]):
        self.name = name
        self.tools = tools
        self.client = openai.OpenAI()
    
    def run(self, task: str) -> str:
        # 创建工具描述
        tool_descriptions = []
        for tool in self.tools:
            tool_descriptions.append({
                "name": tool.__name__,
                "description": tool.__doc__,
                "parameters": tool.__annotations__
            })
        
        # 调用模型
        messages = [
            {
                "role": "system",
                "content": f"""You are {self.name}. You have access to the following tools:
{', '.join([tool['name'] for tool in tool_descriptions])}

When you need to use a tool, respond with the tool name and arguments in the format:
TOOL: tool_name
ARGUMENTS: {{key: value}}"""
            },
            {"role": "user", "content": task}
        ]
        
        while True:
            response = self.client.chat.completions.create(
                model="gpt-4",
                messages=messages
            )
            
            result = response.choices[0].message.content
            
            # 检查是否需要使用工具
            if result.startswith("TOOL:"):
                # 解析工具调用
                lines = result.split("\n")
                tool_name = lines[0].replace("TOOL:", "").strip()
                arguments = json.loads(lines[1].replace("ARGUMENTS:", "").strip())
                
                # 执行工具
                tool = next((t for t in self.tools if t.__name__ == tool_name), None)
                if tool:
                    tool_result = tool(**arguments)
                    
                    # 将工具结果添加到消息中
                    messages.append({"role": "assistant", "content": result})
                    messages.append({"role": "user", "content": f"Tool result: {tool_result}"})
                else:
                    messages.append({"role": "assistant", "content": f"Unknown tool: {tool_name}"})
            else:
                return result

# 定义工具
def search_web(query: str) -> str:
    """Search the web for information"""
    # 实际实现会调用搜索 API
    return f"Search results for: {query}"

def get_current_time() -> str:
    """Get the current time"""
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# 创建 Agent
agent = Agent("Researcher", [search_web, get_current_time])

# 运行 Agent
result = agent.run("What's the weather today and what time is it?")
print(result)

多 Agent 协作

class MultiAgentSystem:
    def __init__(self):
        self.agents = []
        self.client = openai.OpenAI()
    
    def add_agent(self, agent: Agent):
        self.agents.append(agent)
    
    def coordinate(self, task: str) -> str:
        # 分析任务并分配给合适的 Agent
        task_analysis = self._analyze_task(task)
        
        # 找到合适的 Agent
        suitable_agents = self._find_suitable_agents(task_analysis)
        
        # 让 Agent 协作完成任务
        results = []
        for agent in suitable_agents:
            result = agent.run(task)
            results.append({
                "agent": agent.name,
                "result": result
            })
        
        # 整合结果
        return self._integrate_results(task, results)
    
    def _analyze_task(self, task: str) -> Dict:
        # 分析任务类型和需求
        response = self.client.chat.completions.create(
            model="gpt-4",
            messages=[
                {
                    "role": "system",
                    "content": """Analyze the task and return a JSON with the following fields:
{
  "type": "task type",
  "requirements": ["required capabilities"],
  "complexity": "low/medium/high"
}"""
                },
                {"role": "user", "content": f"Task: {task}"}
            ]
        )
        
        return json.loads(response.choices[0].message.content)
    
    def _find_suitable_agents(self, task_analysis: Dict) -> List[Agent]:
        # 根据任务需求找到合适的 Agent
        suitable_agents = []
        
        for agent in self.agents:
            # 检查 Agent 是否有任务所需的工具
            agent_capabilities = [tool.__name__ for tool in agent.tools]
            required_capabilities = task_analysis["requirements"]
            
            if any(cap in agent_capabilities for cap in required_capabilities):
                suitable_agents.append(agent)
        
        return suitable_agents
    
    def _integrate_results(self, task: str, results: List[Dict]) -> str:
        # 整合多个 Agent 的结果
        results_summary = "\n".join([
            f"{result['agent']}: {result['result']}"
            for result in results
        ])
        
        response = self.client.chat.completions.create(
            model="gpt-4",
            messages=[
                {
                    "role": "system",
                    "content": "Integrate the results from multiple agents into a coherent response."
                },
                {
                    "role": "user",
                    "content": f"""Task: {task}

Results:
{results_summary}

Integrated response:"""
                }
            ]
        )
        
        return response.choices[0].message.content

# 使用
system = MultiAgentSystem()

# 添加不同能力的 Agent
research_agent = Agent("Researcher", [search_web])
calculation_agent = Agent("Calculator", [calculate])
time_agent = Agent("Timekeeper", [get_current_time])

system.add_agent(research_agent)
system.add_agent(calculation_agent)
system.add_agent(time_agent)

# 协作完成任务
result = system.coordinate("Calculate 10 + 20, then search for information about the result, and tell me the current time.")
print(result)

踩过的坑

坑一:上下文管理

提示词太长,超出模型限制。

解决:合理截断和压缩上下文。

def truncate_context(context, max_tokens=4000):
    # 简单截断
    if len(context.split()) <= max_tokens:
        return context
    
    # 更智能的方式:保留重要部分
    sentences = context.split('. ')
    truncated = '. '.join(sentences[:len(sentences) // 2])
    return truncated + '.'

坑二:成本控制

API 调用成本太高。

解决:缓存结果,使用更便宜的模型。

from functools import lru_cache

class CachedLLMClient:
    def __init__(self):
        self.client = openai.OpenAI()
    
    @lru_cache(maxsize=1000)
    def completion(self, prompt: str) -> str:
        return self.client.chat.completions.create(
            model="gpt-4",
            messages=[{"role": "user", "content": prompt}]
        ).choices[0].message.content
    
    def cheap_completion(self, prompt: str) -> str:
        # 使用更便宜的模型
        return self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[{"role": "user", "content": prompt}]
        ).choices[0].message.content

坑三:输出解析

模型输出格式不统一。

解决:使用结构化输出和输出解析。

def structured_output(prompt: str, schema: Dict) -> Dict:
    # 使用 Pydantic 或类似工具
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {
                "role": "system",
                "content": f"Return the output in the following JSON format:\n{json.dumps(schema)}"
            },
            {"role": "user", "content": prompt}
        ]
    )
    
    try:
        return json.loads(response.choices[0].message.content)
    except json.JSONDecodeError:
        # 处理解析错误
        return {"error": "Failed to parse output"}

写在最后

大模型应用开发这东西,不只是 API 调用,是新的应用范式。

解决了

  • 自然语言理解
  • 复杂推理任务
  • 个性化交互

带来了

  • 成本问题
  • 可靠性问题
  • 可解释性问题

开发之前先评估:

  • 任务复杂度
  • 成本预算
  • 可靠性要求
  • 可解释性需求

不是所有任务都需要大模型,有时候规则系统更简单。


这次大模型应用开发花了两个月,从简单 API 到复杂 Agent。开发完成后,任务完成时间减少了 70%,用户体验提升明显。

版权声明: 本文首发于 指尖魔法屋-关于大模型应用开发的几点记录https://blog.thinkmoon.cn/post/84-llm-application-development-api-agent-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!