Spring AI, LangChain和LangGraph(三)
·
现代大语言模型(LLM)的 Prompt 并不仅仅是文本,它是一个复合对象.
一、Prompt示例
1️⃣ Spring AI
🎯 场景说明
你要构建一个 RAG 助手,它具备:
-
严格的行为规则
-
使用检索到的文档
-
能调用工具
-
返回强类型结构化输出
-
自动使用对话记忆
① 领域模型(结构化输出 Schema)
public record RagAnswer(
String answer,
List<String> sources
) {}
✅ 结构化输出
✅ 自动校验
✅ 不需要手动解析 JSON
② 工具定义(Tool Instructions)
@Component
public class TimeTools {
@Tool(description = "Get current system time")
public String currentTime() {
return LocalDateTime.now().toString();
}
}
✅ 工具 Schema 会自动注入 Prompt
✅ LLM 只有在需要时才会调用
③ 使用 Advisors 构建 ChatClient(上下文注入)
EmbeddingVectorStore vectorStore = ...;
ChatMemory chatMemory = new InMemoryChatMemory();
ChatClient chatClient = ChatClient.builder(chatModel)
.advisors(
new RetrievalAdvisor(vectorStore), // RAG 检索上下文
new MessageChatMemoryAdvisor(chatMemory) // 对话记忆
)
.build();
这一步隐式注入了:
-
检索到的文档
-
对话历史
⚠️ 注意:你没有在 Prompt 中手写这些内容
④ 执行完整 Prompt(所有特性一起)
RagAnswer result = chatClient.prompt()
// 1️⃣ System message(规则)
.system("""
You are a senior AI tutor.
Answer step-by-step.
Only use provided context.
If unsure, say "I don't know".
""")
// 2️⃣ User message(用户意图)
.user("""
Explain Retrieval-Augmented Generation.
Also tell me the current time if helpful.
""")
// 3️⃣ Tool instructions(隐式)
.tools(TimeTools.class)
// 4️⃣ 强制结构化输出
.call()
.entity(RagAnswer.class);
⑤ LLM 实际“看到”的内容(概念层)
SYSTEM:
You are a senior AI tutor...
CONTEXT(由 Advisors 注入):
[检索文档 1]
[检索文档 2]
[历史对话]
TOOLS:
currentTime() -> string
OUTPUT FORMAT:
{
"answer": string,
"sources": string[]
}
USER:
Explain Retrieval-Augmented Generation...
✅ 这是一个执行契约(Execution Contract)
❌ 不是一个简单的字符串 Prompt
2️⃣ LangChain —— 等价实现(Python)
同样的能力,但显式拼装
① 结构化输出 Schema
from pydantic import BaseModel
from typing import List
class RagAnswer(BaseModel):
answer: str
sources: List[str]
② 工具定义
from langchain.tools import tool
from datetime import datetime
@tool
def current_time() -> str:
"""Get current system time"""
return datetime.now().isoformat()
③ Retriever(上下文注入)
retriever = vectorstore.as_retriever()
④ Prompt 模板(多消息)
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system",
"You are a senior AI tutor. "
"Answer step-by-step. "
"Only use provided context."),
("human", "{question}")
])
⑤ 组合所有组件
llm = chat_model.bind_tools([current_time])
llm = llm.with_structured_output(RagAnswer)
chain = (
{
"context": retriever,
"question": lambda x: x
}
| prompt
| llm
)
result = chain.invoke("Explain Retrieval-Augmented Generation")
3️⃣ 功能对照表(Spring AI vs LangChain)
| 功能 | Spring AI | LangChain |
|---|---|---|
| System 消息 | .system() |
("system", "...") |
| User 消息 | .user() |
("human", "...") |
| Assistant 消息 | 隐式 | AIMessage |
| 工具指令 | .tools() |
bind_tools() |
| 结构化输出 | .entity(Class) |
with_structured_output() |
| RAG 上下文 | RetrievalAdvisor |
显式 retriever |
| 记忆 | MemoryAdvisor |
显式 memory |
✅ 最终模型
Prompt =
行为规则
+ 能力(工具)
+ 记忆
+ 检索知识
+ 输出契约
+ 用户意图
👉 你不是在“写提示词”
👉 你是在“编程 AI 的行为”
二、再深入解释
1️⃣ 为什么这不再是「Prompt 字符串」?
传统做法:
String prompt = "You are an AI, answer this question...";
❌ 问题:
-
无法约束输出
-
无法注入工具
-
无法复用记忆
-
无法控制上下文来源
-
不可测试、不可维护
现代 Prompt 的本质
👉 一次 LLM 调用 = 一个执行契约
它包含:
-
输入(消息 + 上下文)
-
能力(工具)
-
约束(结构化输出)
-
状态(记忆)
就像调用一个函数:
RagAnswer answer = ai.execute(contract);
2️⃣ Spring AI vs LangChain 的核心差异
Spring AI:隐式 + 强类型
-
Advisor 自动注入上下文
-
Java record 直接做输出
-
非常适合企业、后端、DDD
LangChain:显式 + 函数式
-
所有步骤自己拼
-
更灵活、实验性强
-
适合 Python、研究、Agent flow
👉 能力是一样的,哲学不同
3️⃣ Tool 为什么不是“函数调用字符串”?
你不是在告诉模型:
“调用 currentTime()”
你是在告诉模型:
「你有一个能力,可以在需要时使用」
模型会:
-
判断是否需要工具
-
生成 Tool Call
-
框架执行
-
结果回注入上下文
4️⃣ Structured Output = 类型安全的 AI
没有结构化输出:
{
"answer": "maybe...",
"source": "???"
}
❌ 崩溃在生产环境
有结构化输出:
RagAnswer answer = result;
✅ 编译期 + 运行期安全
5️⃣ 一句话总结
Prompt Engineering 已经结束了
Prompt Programming 才刚开始
更多推荐



所有评论(0)