Agent开发核心能力攻坚—— 从Prompt Engineering到Memory机制全解析
拆解 Agent 的四根支柱:Prompt · 工具 · 循环 · 记忆
一、阶段概览
L2 进阶阶段聚焦 Agent 开发四大核心能力:Prompt Engineering、Function Calling、Agent Framework、Memory 机制。从"让 LLM 听懂话"到"让 Agent 记住对话",构建完整的 Agent 应用认知体系。
| 模块 | 主题 | 核心交付 | 难度 |
|---|---|---|---|
| 2.1 | Prompt Engineering | 追问、示例注入、角色扮演 | ⭐⭐ |
| 2.2 | Function Calling | 工具调用、JSON Schema、ToolMessage | ⭐⭐⭐ |
| 2.3 | Agent Framework | ReAct、LangChain 源码、Streaming | ⭐⭐⭐⭐ |
| 2.4 | Memory 机制 | 滑动窗口、摘要压缩、三层架构 | ⭐⭐⭐ |
二、Module 2.1:Prompt Engineering
2.1.1 核心概念
Prompt Engineering 是通过构造输入文本控制 LLM 输出行为的技术。它不改变模型参数,而是改变模型的"输入上下文"。
三种核心策略:
- 追问(Chain-of-Thought Prompting):引导 LLM 分步推理
- 示例注入(Few-Shot Prompting):在 prompt 中提供格式范例
- 角色扮演(Role Prompting):通过 System Prompt 设定角色身份
2.1.2 System Prompt vs User Prompt
┌─────────────────────────────────────┐
│ System Prompt(角色设定,一次定义) │
│ "你是一个天气预报助手..." │
├─────────────────────────────────────┤
│ User Prompt(用户输入,每次不同) │
│ "北京今天天气怎么样?" │
└─────────────────────────────────────┘
System Prompt 优先级高于 User Prompt,用于设定模型行为边界和回答风格。
2.1.3 关键技术点
- Prompt Template:用
{variable}占位符动态注入变量 - Few-Shot 注入:
messages.insert(1, {"role": "user", ...})在历史开头插入示例 - 追问链:
"请一步步思考"→ 触发 CoT 推理
三、Module 2.2:Function Calling
3.1 工作原理
Function Calling 让 LLM 不直接回答,而是输出一个结构化的工具调用请求,由程序执行工具后将结果返回给 LLM,形成闭环。
User: "北京天气?"
→ LLM: tool_calls=[{function: "get_weather", arguments: '{"city":"北京"}'}]
→ 程序: 执行 get_weather("北京") → "25°C 晴"
→ LLM: "北京今天25°C,晴天"
3.2 关键数据结构
// 工具定义(发往 LLM)
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名"}
},
"required": ["city"]
}
}
}
// LLM 返回的 tool_calls(不是最终回答!)
{
"finish_reason": "tool_calls", // 不是 "stop"
"message": {
"tool_calls": [{
"id": "call_00_TBjxbbNaggp4JVevRoMNDuLi", // 必须用真实 id
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}" // JSON 字符串,需 json.loads()
}
}]
}
}
3.3 核心坑点
| 坑 | 说明 |
|---|---|
finish_reason 判断 |
tool_calls ≠ stop,必须继续循环 |
tool_call_id |
必须用 LLM 返回的真实 id,不能伪造 |
arguments 解析 |
是 JSON 字符串,需 json.loads() 反序列化 |
| 消息历史 | 每轮需追加 assistant(含 tool_calls)+ tool(结果)两条消息 |
四、Module 2.3:Agent Framework
4.1 Agent Loop 状态机
Agent 的核心是一个循环状态机:
┌──────────────────────────────────┐
│ │
▼ │
┌─────────┐ tool_calls ┌──────────┐ │
│ call LLM │──────────────→│ execute │ │
│ │ │ tools │ │
└─────────┘ └──────────┘ │
│ │ │
│ stop │results│
▼ ▼ │
┌─────────┐ ┌──────────┐ │
│ return │ │ append │───┘
│ answer │ │ messages │
└─────────┘ └──────────┘
伪代码:
while True:
response = llm.chat(messages, tools=tools)
if response.finish_reason == "stop":
return response.content
elif response.finish_reason == "tool_calls":
messages.append(response.message) # assistant 消息
for tc in response.tool_calls:
result = execute_tool(tc.name, tc.arguments)
messages.append(ToolMessage(result, tc.id)) # tool 结果
4.2 LangChain 7 层调用链
LangChain 的 ChatDeepSeek.invoke() 并非黑盒,其内部调用链为:
| 层 | 组件 | 职责 | Java 对照 |
|---|---|---|---|
| L1 | invoke() |
模板方法:retry + callback 包装 | @Transactional 切面 |
| L2 | _generate() |
核心:Message → OpenAI JSON dict | Controller.handle() |
| L3 | _convert_messages() |
类型转换:HumanMessage → role:user | ObjectMapper.writeValue() |
| L4 | _format_tools() |
Python 函数 → OpenAI tool schema | Swagger/OpenAPI Schema Gen |
| L5 | OpenAI SDK | URL + headers 构造 | RestTemplate.exchange() |
| L6 | httpx.Client.post() |
HTTP 请求发送 | HttpURLConnection |
| L7 | TCP Socket | 字节流 → api.deepseek.com |
Socket.connect() |
L3 转换规则:
| LangChain Message | OpenAI JSON |
|---|---|
HumanMessage("你好") |
{"role": "user", "content": "你好"} |
AIMessage("你好!") |
{"role": "assistant", "content": "你好!"} |
ToolMessage("结果", tool_call_id="...") |
{"role": "tool", "content": "结果", "tool_call_id": "..."} |
4.3 Streaming SSE 机制
Non-Streaming vs Streaming 的核心差异:
Non-Streaming: Client ──POST──→ Server ──完整JSON──→ Client (一次返回)
Streaming: Client ──POST──→ Server ──chunk1──→
──chunk2──→ Client (逐块接收)
──chunk3──→
SSE 格式:
data: {"choices":[{"delta":{"content":"北"},"index":0}]}
data: {"choices":[{"delta":{"content":"京"},"index":0}]}
data: {"choices":[{"delta":{"content":"今"},"index":0}]}
...
data: [DONE]
Streaming 最大坑点:tool_calls 碎片化
tool_calls 的 name 和 arguments 可能分布在多个 chunk 中:
chunk1: tool_calls[0].function.name = "get"
chunk2: tool_calls[0].function.name = "_weather" ← 拼接!
chunk3: tool_calls[0].function.arguments = "{\"cit"
chunk4: tool_calls[0].function.arguments = "y\":\"北京\"}"
解决:ToolCallAccumulator——等 finish_reason 出现后再组装完整 tool_calls。
4.4 多 Tool Call 并发
# 单工具(串行) vs 多工具(并发)
with ThreadPoolExecutor() as pool:
futures = {
pool.submit(execute_tool, tc): tc
for tc in tool_calls
}
for future in as_completed(futures):
results.append(future.result())
Java 对照:CompletableFuture.allOf()
五、Module 2.4:Memory 机制
5.1 核心概念
LLM 本身无状态——每次 API 调用是独立的。Memory 将历史对话在每次请求时动态注入 messages 列表,让 LLM "看起来"记住了对话。
5.2 短期记忆 vs 长期记忆
| 维度 | 短期记忆 | 长期记忆 |
|---|---|---|
| 生命周期 | 进程内,关闭消失 | 持久化,跨会话 |
| 存储 | list[dict] |
数据库 / 文件 / 向量库 |
| 类比 Java | HttpSession |
MySQL / Redis |
| Token 压力 | 全部携带 | 按需检索 |
5.3 滑动窗口截断
当历史消息超出限制时,按窗口保留最近 N 条:
WINDOW_SIZE = 10
if len(history) > WINDOW_SIZE:
history = history[-WINDOW_SIZE:] # 只保留最近10条
5.4 摘要压缩
用 LLM 将长历史压缩为一段摘要,保留摘要 + 最近几条消息:
原始: [msg1, msg2, ..., msg500]
压缩: [{"role":"system","content":"摘要:用户问了天气..."},
{"role":"user","content":"最近一条消息"}]
5.5 三层记忆架构
┌────────────────────────────────────┐
│ Layer 1: 当前会话消息 │ ← messages list(每次请求携带)
├────────────────────────────────────┤
│ Layer 2: Session Store │ ← 文件/SQLite(跨会话短期记忆)
├────────────────────────────────────┤
│ Layer 3: 知识库 │ ← 向量数据库(RAG 检索增强)
└────────────────────────────────────┘
5.6 LangChain Memory 家族
| 类 | 策略 | 适用场景 |
|---|---|---|
BufferMemory |
全量保留 | 短对话 |
ConversationTokenBufferMemory |
按 token 数截断 | 中长对话 |
ConversationSummaryMemory |
LLM 压缩摘要 | 超长对话 |
VectorStoreRetrieverMemory |
向量检索 | 知识库/FAQ |
六、技术对照表
6.1 LLM 交互协议
| Python | Java |
|---|---|
httpx.Client.post() |
RestTemplate.exchange() |
SSE iter_lines() |
WebClient + Flux<ServerSentEvent> |
json.loads(arguments) |
Jackson ObjectMapper |
ThreadPoolExecutor |
CompletableFuture.allOf() |
6.2 架构模式
| Python LangChain | Java Spring |
|---|---|
create_agent() |
@Service.process() |
_convert_messages() |
ObjectMapper.writeValue() |
tool_calls loop |
状态机(Spring State Machine) |
| BufferMemory | HttpSession.setAttribute() |
七、阶段成果
- 理解 System/User Prompt 分层设计
- 掌握 Function Calling 完整闭环(含 3 个核心坑点)
- 手写 Agent Loop(httpx + DeepSeek API)
- LangChain 7 层调用链逆向到 TCP 层
- Streaming SSE 逐 token 接收与 ToolCallAccumulator
- 多 tool_call ThreadPoolExecutor 并发执行
- Memory 三层架构:会话消息 / Session Store / 知识库
- 滑动窗口截断 + LLM 摘要压缩
八、L3 预告
| 模块 | 主题 | 说明 |
|---|---|---|
| 3.1 | RAG 基础 | 手写 sentence-transformers + chromadb 管线 |
| 3.2 | 多 Agent 协作 | CrewAI / AutoGen 多 Agent 编排 |
| 3.3 | Agent 工具生态 | MCP 协议 / 工具插件化 |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)