
随着大语言模型(LLM)能力的跃升,基于LLM的智能体(Agent)已成为构建自动化工作流、交互式应用的核心范式。然而,绝大多数Demo停留在单轮对话或固定脚本,真正走向生产环境时,工程化挑战接踵而至:状态管理、工具扩展、记忆持久化、可观测性、容错与回退……本文不空谈概念,而是结合AI编程(利用AI辅助编码工具如Cursor、Copilot)的实战经验,带你从零搭建一个可投产的企业级Agent框架。全文代码基于Python 3.11 + LangChain + FastAPI,并融入Docker、Prometheus等云原生技术栈。
一个生产级Agent需要解决:
本文将逐一攻克这些痛点,最终交付一个支持流式响应+工具调用+记忆检索的HTTP服务。
我们采用六边形架构,将Agent拆解为四层:
┌─────────────────────────────────────────────┐
│ API Layer (FastAPI) │
│ - 会话管理 / 流式SSE / 鉴权 │
└─────────────────┬───────────────────────────┘
┌─────────────────▼───────────────────────────┐
│ Orchestrator (ReAct + Plan-Execute) │
│ - 推理循环 / 工具选择 / 错误重试 │
└─────────────────┬───────────────────────────┘
┌─────────────────▼───────────────────────────┐
│ Memory & Context │
│ - 短期:Redis (会话状态) │
│ - 长期:PGVector (向量记忆) │
└─────────────────┬───────────────────────────┘
┌─────────────────▼───────────────────────────┐
│ Tool Registry (可插拔工具集) │
│ - 内置:计算器 / 搜索 / 数据库查询 │
│ - 自定义:业务微服务调用 │
└─────────────────────────────────────────────┘每层通过依赖注入解耦,便于单元测试和替换实现。
定义标准工具接口,支持同步/异步执行,并自带参数校验(Pydantic):
from typing import Any, Type, Optional
from pydantic import BaseModel, Field
from abc import ABC, abstractmethod
class ToolInput(BaseModel):
"""所有工具输入必须继承"""
pass
class BaseTool(ABC):
name: str
description: str
input_schema: Type[ToolInput]
@abstractmethod
async def arun(self, **kwargs) -> str:
"""异步执行,返回可读结果"""
pass
def to_openai_schema(self) -> dict:
"""转换为OpenAI function calling格式"""
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.input_schema.model_json_schema()
}
}实战工具:查询内部订单系统
class OrderQueryInput(ToolInput):
order_id: str = Field(..., description="订单号,如ORD-2026-001")
include_items: bool = Field(False, description="是否包含商品明细")
class OrderQueryTool(BaseTool):
name = "query_order"
description = "根据订单号查询订单状态和基本信息"
input_schema = OrderQueryInput
async def arun(self, order_id: str, include_items: bool = False) -> str:
# 模拟实际微服务调用(带熔断+重试)
async with aiohttp.ClientSession() as session:
try:
async with session.get(
f"http://order-svc/orders/{order_id}",
params={"items": str(include_items).lower()},
timeout=5.0
) as resp:
data = await resp.json()
return f"订单状态:{data['status']},总金额:{data['total']}"
except asyncio.TimeoutError:
return "查询超时,请稍后重试"这里实现向量记忆检索器,用于在每次推理前注入相关历史:
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import PGVector
class LongTermMemory:
def __init__(self, connection_string: str):
self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
self.store = PGVector(
connection_string=connection_string,
embedding_function=self.embeddings,
collection_name="agent_memories"
)
async def add_memory(self, user_input: str, agent_response: str):
"""将交互对存入向量库,附带元数据(时间戳、会话ID)"""
text = f"Q: {user_input}\nA: {agent_response}"
await asyncio.to_thread(
self.store.add_texts,
texts=[text],
metadatas=[{"timestamp": datetime.utcnow().isoformat()}]
)
async def retrieve_relevant(self, query: str, k: int = 3) -> List[str]:
"""检索与当前问题最相关的历史记忆"""
docs = await asyncio.to_thread(
self.store.similarity_search, query, k=k
)
return [doc.page_content for doc in docs]我们实现一个可配置的AgentOrchestrator,支持流式推理、工具调用循环、最大步数限制、回退策略。
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import JsonOutputParser
import json
class AgentOrchestrator:
def __init__(self, tools: List[BaseTool], memory: LongTermMemory, redis_client):
self.tools = {t.name: t for t in tools}
self.llm = ChatOpenAI(model="gpt-4o", temperature=0.2, streaming=True)
self.memory = memory
self.redis = redis_client
self.max_iterations = 5
async def run(self, user_input: str, session_id: str, stream_callback=None):
"""主入口:执行ReAct循环,支持流式回调"""
# 1. 加载短期对话历史(Redis)
history = self._get_short_term(session_id) # List[dict]
# 2. 检索长期记忆
memories = await self.memory.retrieve_relevant(user_input)
memory_context = "\n".join(memories) if memories else ""
# 3. 构造系统提示(包含工具描述和记忆)
system_prompt = self._build_system_prompt(memory_context)
# 4. 初始化消息列表
messages = [SystemMessage(content=system_prompt)] + history + [HumanMessage(content=user_input)]
# 5. 迭代推理-行动-观察
step = 0
final_answer = None
while step < self.max_iterations:
step += 1
# 调用LLM(流式输出思考过程)
if stream_callback:
await stream_callback({"type": "thinking", "step": step, "content": "正在分析..."})
# 请求函数调用
response = await self.llm.ainvoke(
messages,
tools=[t.to_openai_schema() for t in self.tools.values()],
tool_choice="auto"
)
# 记录助手消息
messages.append(response)
# 判断是否有工具调用
if not response.tool_calls:
# 最终回答
final_answer = response.content
break
# 执行工具调用(并行支持)
tool_results = await self._execute_tools(response.tool_calls)
for tc, result in zip(response.tool_calls, tool_results):
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"content": result
})
if stream_callback:
await stream_callback({"type": "tool_result", "tool": tc["name"], "result": result})
# 6. 保存本次交互到短期+长期记忆
await self._save_interaction(session_id, user_input, final_answer or "无回答")
return final_answer
async def _execute_tools(self, tool_calls: List[dict]) -> List[str]:
"""并行执行多个工具调用"""
tasks = []
for tc in tool_calls:
tool_name = tc["name"]
args = json.loads(tc["arguments"])
tool = self.tools.get(tool_name)
if not tool:
tasks.append(self._error_result(f"未知工具: {tool_name}"))
else:
tasks.append(tool.arun(**args))
return await asyncio.gather(*tasks, return_exceptions=True)
def _build_system_prompt(self, memory_context: str) -> str:
return f"""
你是一个智能助手,可以调用以下工具来完成任务:
{self._tool_descriptions()}
额外参考历史记忆(仅供背景参考):
{memory_context}
请遵循ReAct模式,先思考再行动。如果工具调用失败,尝试替代方案。最终答案要简明。
"""提供/chat/stream端点,返回Server-Sent Events,实时推送思考、工具调用、最终结果。
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
app = FastAPI()
orchestrator = AgentOrchestrator(...) # 依赖注入
class ChatRequest(BaseModel):
message: str
session_id: str = "default"
@app.post("/chat/stream")
async def chat_stream(req: ChatRequest):
async def event_generator():
async def callback(event_data: dict):
yield f"data: {json.dumps(event_data)}\n\n"
answer = await orchestrator.run(
user_input=req.message,
session_id=req.session_id,
stream_callback=callback
)
yield f"data: {json.dumps({'type': 'final', 'content': answer})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")将系统提示、工具描述模板单独存放为YAML,支持动态切换。编写回归测试集(含期望的工具调用序列),每次PR自动运行:
# prompts/v1.yaml
system_template: |
你是一个智能助手...
{memory_context}
Available tools: {tools}测试用例(pytest + 模拟LLM响应):
def test_order_query_flow(mocker):
mock_llm = mocker.AsyncMock()
mock_llm.ainvoke.return_value = MagicMock(
tool_calls=[{"name": "query_order", "arguments": '{"order_id":"ORD-001"}'}]
)
orch = AgentOrchestrator(llm=mock_llm, ...)
result = asyncio.run(orch.run("查订单ORD-001", "sess1"))
assert "订单状态" in result示例:装饰器自动埋点
from opentelemetry import trace
tracer = trace.get_tracer("agent.orchestrator")
@tracer.start_as_current_span("agent_run")
async def run(self, ...):
with tracer.start_span("llm_call") as span:
span.set_attribute("model", "gpt-4o")
response = await self.llm.ainvoke(...)
span.set_attribute("token_usage", response.usage.total_tokens)asyncio.timeout)tenacity库)@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=5))
async def call_llm_with_retry(self, messages):
return await self.llm.ainvoke(messages)本文的代码框架,实际上有约40%的核心逻辑(如AgentOrchestrator模板、Pydantic模型)是由AI编程助手生成的。但关键在于工程师的引导:
BaseTool抽象类,让AI生成具体工具实现我们内部沉淀了一套Agent工程化提示词模板,比如:
请实现一个异步工具类,用于调用REST API,要求:
- 继承BaseTool
- 输入参数使用Pydantic校验,包括必填和可选
- 异常处理转为友好错误消息
- 添加详细的日志记录这样,AI生成的代码可直接集成,工程效率提升50%以上。
提供Dockerfile,构建轻量级镜像(基于python:3.11-slim)。集成健康检查端点/health,就绪探针检查Redis/PG连接。
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Github Actions流水线包含:
aiocache装饰器,TTL 60s本文完整呈现了一个生产级Agent的工程化方案,涵盖:
这套体系已在我们的客户服务、运维自动化场景稳定运行,日均处理10万+请求,平均响应时间<2.5s,工具调用成功率99.2%。未来我们将探索多Agent协作和自适应提示词优化,进一步释放LLM的潜力。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。