Go并发编程在微服务中的应用 - 从理论到实践
与传统程序不同,智能体不仅仅是被动执行预设指令,而是具备一定程度的自主性和适应性,能够在复杂、多变的环境中不断优化行为。无论是任务分解、知识获取,还是与外部工具的协同,都会结合实际案例,帮助你理解如何打造一个真正能落地、能进化的智能体。它模拟了人类作者“写—审—改”的迭代过程:一个模型负责生成候选答案,另一个模型则充当评估员,给出改进建议,二者循环迭代,直到得到令人满意的结果。简而言之,评估器–优
概述
在智能体逐渐成为人工智能应用核心的今天,如何让它“聪明”且“高效”是开发者最关心的问题。本文将带你从设计思路、核心能力到工程实践,全面解析高效智能体的构建方法。无论是任务分解、知识获取,还是与外部工具的协同,都会结合实际案例,帮助你理解如何打造一个真正能落地、能进化的智能体。
2.内容
2.1 什么是智能体
智能体(Agent)是人工智能领域中的核心概念,可以理解为一种具备 感知、决策和执行能力的自主系统。它能够从环境中获取信息,结合自身的知识或模型进行推理和判断,并通过调用工具或执行操作来完成任务。与传统程序不同,智能体不仅仅是被动执行预设指令,而是具备一定程度的自主性和适应性,能够在复杂、多变的环境中不断优化行为。
在实际应用中,智能体的使用场景非常广泛:
对话交互:例如智能客服或AI助手,能够理解用户需求并给出合适的回应;
任务自动化:如自动化办公、数据分析、代码生成,帮助人类提高效率;
智能决策:在金融风控、供应链优化、推荐系统中,智能体可以快速处理复杂数据并做出判断;
虚拟与现实结合:从游戏NPC到智能机器人,智能体能够与真实世界或虚拟环境交互,带来更智能的体验。
简而言之,智能体的核心价值在于 替人类完成复杂任务、提升效率和创造力,它正逐渐成为AI应用的关键载体。
2.2 何时使用智能体以及智能体框架
并不是所有问题都需要引入智能体,有些场景用普通脚本或固定规则就能解决。但当任务具备 复杂性、动态性和不确定性 时,智能体和智能体框架就展现出独特优势。
适合使用智能体的典型场景:
1. 任务复杂、需要自主规划
例如在 数据分析 中,不仅要获取数据,还要清洗、建模、可视化。传统脚本需要逐步编写流程,而智能体可以根据目标自动分解任务,并灵活调用工具完成每个环节。
2. 环境动态、信息来源多样
在 金融风控 中,数据源包含市场行情、新闻资讯、历史交易记录,信息随时变化。智能体能持续监控并动态调整策略。
3. 需要多轮交互与记忆
在 智能客服 或 教育辅导 场景中,用户问题往往连续且上下文相关,智能体通过框架中的“记忆机制”保持连贯性,而不是每次都从零开始。
4. 需要调用多种外部工具或API
比如在 软件研发 中,智能体能先检索文档,再调用代码生成工具,最后利用测试框架验证结果,形成一个完整闭环。
智能体框架的价值 在于降低开发门槛。它提供了任务调度、插件管理、上下文记忆等通用能力,让开发者可以专注于业务逻辑。例如:
LangChain 适合构建多步推理与工具调用场景;
AutoGen 擅长多智能体协作;
LlamaIndex 在知识库问答中表现突出。
当你的问题是 一次性、结构化、固定逻辑 → 用传统脚本即可;
当你的问题是 多步骤、不确定性强、需要灵活应对 → 就是使用智能体和框架的好时机。
3.智能体模式
3.1 链式工作流智能体
Prompt Chaining 工作流模式 是在大型语言模型(LLM)应用开发中常见且高效的一种设计思路。其核心理念是:将复杂的任务 分解为一系列有机衔接的步骤,每个步骤由一次 LLM 调用完成,并且后续步骤会基于前一步的输出继续处理。
image
提示链(Prompt Chaining)模式 在以下几类场景中尤为适用:
任务复杂度高:当问题难以一次性解决时,可以将其拆解为一系列更简单、可控的步骤;
需要逐步验证:每个中间输出都可能需要检查、修正或转换,确保最终结果的准确性;
保持清晰链路:通过分步骤衔接,能够清楚追踪数据或逻辑的流转过程,避免“黑箱式”结果。
例如,下述案例展示了一个针对 文本中数值数据处理 的四步工作流:
提取数值和指标 —— 从原始文本中识别出数字及其对应的含义;
标准化格式 —— 将不同表示方式统一为百分比格式,确保结果一致;
排序处理 —— 按照数值大小进行降序排序,便于后续分析;
结果输出 —— 将整理好的数据转换为 Markdown 表格,便于展示与阅读。
通过这种链式调用方式,复杂的数据处理过程被拆分为结构清晰、可追踪的步骤,既提升了 准确性和可维护性,又让开发者能够灵活地对每一环节进行优化和扩展。
具体实现代码如下所示:
复制代码
import org.springframework.ai.chat.client.ChatClient;
public class ChainWorkflow {
/**
* Array of system prompts that define the transformation steps in the chain.
* Each prompt acts as a gate that validates and transforms the output before
* proceeding to the next step.
*/
private static final String[] DEFAULT_SYSTEM_PROMPTS = {
// Step 1
"""
Extract only the numerical values and their associated metrics from the text.
Format each as'value: metric' on a new line.
Example format:
92: customer satisfaction
45%: revenue growth""",
// Step 2
"""
Convert all numerical values to percentages where possible.
If not a percentage or points, convert to decimal (e.g., 92 points -> 92%).
Keep one number per line.
Example format:
92%: customer satisfaction
45%: revenue growth""",
// Step 3
"""
Sort all lines in descending order by numerical value.
Keep the format 'value: metric' on each line.
Example:
92%: customer satisfaction
87%: employee satisfaction""",
// Step 4
"""
Format the sorted data as a markdown table with columns:
| Metric | Value |
|:--|--:|
| Customer Satisfaction | 92% | """
};
private final ChatClient chatClient;
private final String[] systemPrompts;
public ChainWorkflow(ChatClient chatClient) {
this(chatClient, DEFAULT_SYSTEM_PROMPTS);
}
public ChainWorkflow(ChatClient chatClient, String[] systemPrompts) {
this.chatClient = chatClient;
this.systemPrompts = systemPrompts;
}
public String chain(String userInput) {
int step = 0;
String response = userInput;
System.out.println(String.format("\nSTEP %s:\n %s", step++, response));
for (String prompt : systemPrompts) {
// 1. Compose the input using the response from the previous step.
String input = String.format("{%s}\n {%s}", prompt, response);
// 2. Call the chat client with the new input and get the new response.
response = chatClient.prompt(input).call().content();
System.out.println(String.format("\nSTEP %s:\n %s", step++, response));
}
return response;
}
}
复制代码
主服务入口代码实现:
复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
// ------------------------------------------------------------
// PROPMT CHAINING WORKFLOW
// ------------------------------------------------------------
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
String report = """
Q3 Performance Summary:
Our customer satisfaction score rose to 92 points this quarter.
Revenue grew by 45% compared to last year.
Market share is now at 23% in our primary market.
Customer churn decreased to 5% from 8%.
New user acquisition cost is $43 per user.
Product adoption rate increased to 78%.
Employee satisfaction is at 87 points.
Operating margin improved to 34%.
""";
@Bean
public CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
return args -> {
new ChainWorkflow(chatClientBuilder.build()).chain(report);
};
}
}
复制代码
该示例通过一系列提示来处理第三季度的绩效报告。以下是示例输入:
复制代码
Q3 Performance Summary:
Our customer satisfaction score rose to 92 points this quarter.
Revenue grew by 45% compared to last year.
Market share is now at 23% in our primary market.
Customer churn decreased to 5% from 8%.
New user acquisition cost is $43 per user.
Product adoption rate increased to 78%.
Employee satisfaction is at 87 points.
Operating margin improved to 34%.
复制代码
工作流程通过四个步骤来处理此问题:
1.提取值:提取数值及其指标
复制代码
92: customer satisfaction
45%: revenue growth
23%: market share
5%: customer churn
43: user acquisition cost
78%: product adoption
87: employee satisfaction
34%: operating margin
复制代码
2.标准化格式:将适用的值转换为百分比
复制代码
92%: customer satisfaction
45%: revenue growth
23%: market share
5%: customer churn
78%: product adoption
87%: employee satisfaction
34%: operating margin
复制代码
3.排序:按降序排列值
复制代码
92%: customer satisfaction
87%: employee satisfaction
78%: product adoption
45%: revenue growth
34%: operating margin
23%: market share
5%: customer churn
复制代码
4.格式:创建 markdown 表
复制代码
| Metric | Value |
|:--|--:|
| Customer Satisfaction | 92% |
| Employee Satisfaction | 87% |
| Product Adoption | 78% |
| Revenue Growth | 45% |
| Operating Margin | 34% |
| Market Share | 23% |
| Customer Churn | 5% |
复制代码
3.2 评估器-优化器智能体
image
评估器–优化器模式(Evaluator–Optimizer Pattern) 是一种典型的 双 LLM 协作工作流。它模拟了人类作者“写—审—改”的迭代过程:一个模型负责生成候选答案,另一个模型则充当评估员,给出改进建议,二者循环迭代,直到得到令人满意的结果。
该模式包含两个核心组件:
生成器 LLM(Optimizer/Generator):负责为任务生成初始响应,并在收到反馈后进行改进;
评估员 LLM(Evaluator):根据预设的质量标准(如准确性、逻辑性、风格或完整性)对响应进行分析,并输出具体的改进意见。
工作机制如下:
初始生成 —— 生成器 LLM 根据任务需求给出初稿;
质量评估 —— 评估员 LLM 审查初稿,基于评估标准给出反馈;
改进迭代 —— 如果结果不符合要求,生成器根据反馈重新生成内容;
收敛输出 —— 当评估员确认结果达到满意水平时,最终答案被采纳。
这种模式的优势在于:
提升结果质量:避免“一次性生成”的粗糙输出,通过多轮改进获得更佳结果;
增强鲁棒性:减少模型幻觉或逻辑错误;
灵活性高:评估标准可以根据不同任务(如代码正确性、文本风格、数据完整性)进行定制。
应用场景示例:
内容创作:生成文章后由评估员检查逻辑流畅性和语言风格,再反复打磨;
代码生成:评估员负责检测语法错误和单元测试结果,生成器根据反馈修复代码;
问答系统:确保答案不仅正确,还要清晰、全面。
简而言之,评估器–优化器模式就像“作者与编辑”的协作,前者负责创作,后者负责把关,两者交替工作,最终产出高质量成果。
image
评估器–优化器模式 在以下场景中特别适用:
有明确的质量标准:当任务结果能够通过清晰的指标(如正确性、逻辑性、风格或一致性)进行评估时;
迭代能带来显著改进:输出质量在多轮反馈中能逐步优化,而不是“一次生成定型”;
任务需要深度审查:复杂问题往往需要多轮批评与修正,才能得到高质量的结果。
示例应用
文学翻译:在直译之外捕捉语境和风格的细微差别,通过多轮优化更贴近原文意境;
复杂搜索与分析:如学术研究或市场调研,需要多次筛选、比对和总结;
代码生成与调试:初始生成后经过系统性审查,逐步修复语法错误、逻辑漏洞或性能问题;
内容创作:写作往往需要多次草稿与润色,模型在迭代过程中可不断提升逻辑连贯性和表达质量。
简而言之,当任务 可以被客观评估 且 质量提升依赖迭代打磨 时,这种模式能显著提高最终成果的可靠性与可用性。
具体实现代码如下:
复制代码
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EvaluatorOptimizer {
private static final Logger logger = LoggerFactory.getLogger(EvaluatorOptimizer.class);
public static final String DEFAULT_GENERATOR_PROMPT = """
Your goal is to complete the task based on the input. If there are feedback
from your previous generations, you should reflect on them to improve your solution.
CRITICAL: Your response must be a SINGLE LINE of valid JSON with NO LINE BREAKS except those explicitly escaped with \\n.
Here is the exact format to follow, including all quotes and braces:
{"thoughts":"Brief description here","response":"public class Example {\\n // Code here\\n}"}
Rules for the response field:
1. ALL line breaks must use \\n
2. ALL quotes must use \\"
3. ALL backslashes must be doubled: \\
4. NO actual line breaks or formatting - everything on one line
5. NO tabs or special characters
6. Java code must be complete and properly escaped
Example of properly formatted response:
{"thoughts":"Implementing counter","response":"public class Counter {\\n private int count;\\n public Counter() {\\n count = 0;\\n }\\n public void increment() {\\n count++;\\n }\\n}"}
Follow this format EXACTLY - your response must be valid JSON on a single line.
""";
public static final String DEFAULT_EVALUATOR_PROMPT = """
Evaluate this code implementation for correctness, time complexity, and best practices.
Ensure the code have proper javadoc documentation.
Respond with EXACTLY this JSON format on a single line:
{"evaluation":"PASS, NEEDS_IMPROVEMENT, or FAIL", "feedback":"Your feedback here"}
The evaluation field must be one of: "PASS", "NEEDS_IMPROVEMENT", "FAIL"
Use "PASS" only if all criteria are met with no improvements needed.
""";
public static final int MAX_ITERATIONS = 10;
public enum Evaluation {
PASS, NEEDS_IMPROVEMENT, FAIL
}
public record EvaluationResponse(Evaluation evaluation, String feedback) {}
public record RefinedResponse(String solution, List chainOfThought) {}
public record Generation(String thoughts, String response) {}
private final ChatClient chatClient;
private final String generatorPrompt;
private final String evaluatorPrompt;
private final int maxIterations;
public EvaluatorOptimizer(ChatClient chatClient) {
this(chatClient, DEFAULT_GENERATOR_PROMPT, DEFAULT_EVALUATOR_PROMPT, MAX_ITERATIONS);
}
public EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt, String evaluatorPrompt) {
this(chatClient, generatorPrompt, evaluatorPrompt, MAX_ITERATIONS);
}
public EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt,
String evaluatorPrompt, int maxIterations) {
Assert.notNull(chatClient, "ChatClient must not be null");
Assert.hasText(generatorPrompt, "Generator prompt must not be empty");
Assert.hasText(evaluatorPrompt, "Evaluator prompt must not be empty");
Assert.isTrue(maxIterations > 0, "Max iterations must be positive");
this.chatClient = chatClient;
this.generatorPrompt = generatorPrompt;
this.evaluatorPrompt = evaluatorPrompt;
this.maxIterations = maxIterations;
}
public RefinedResponse loop(String task) {
return loop(task, new ArrayList<>(), new ArrayList<>(), 0);
}
private RefinedResponse loop(String task, List memory,
List chainOfThought, int iteration) {
if (iteration >= maxIterations) {
logger.warn("Max iterations ({}) reached without finding a PASS solution", maxIterations);
return new RefinedResponse(getBestSolution(memory), chainOfThought);
}
String context = buildContext(memory, chainOfThought);
Generation generation = generate(task, context);
memory.add(generation.response());
chainOfThought.add(generation);
EvaluationResponse evaluation = evaluate(generation.response(), task);
if (evaluation.evaluation() == Evaluation.PASS) {
logger.info("Solution accepted after {} iterations", iteration + 1);
return new RefinedResponse(generation.response(), chainOfThought);
}
logger.debug("Iteration {}: Evaluation {}", iteration + 1, evaluation.evaluation());
return loop(task, memory, chainOfThought, iteration + 1);
}
private String buildContext(List memory, List chainOfThought) {
if (memory.isEmpty()) {
return "";
}
StringJoiner context = new StringJoiner("\n");
context.add("Previous attempts and feedback:");
for (int i = 0; i < memory.size(); i++) {
context.add(String.format("Attempt %d:", i + 1));
context.add("Code: " + memory.get(i));
if (i < chainOfThought.size()) {
context.add("Thoughts: " + chainOfThought.get(i).thoughts());
}
}
return context.toString();
}
private Generation generate(String task, String context) {
try {
Generation generation = chatClient.prompt()
.user(u -> u.text("{prompt}\n{context}\nTask: {task}")
.param("prompt", generatorPrompt)
.param("context", context)
.param("task", task))
.call()
.entity(Generation.class);
logGeneration(generation);
return generation;
} catch (Exception e) {
logger.error("Generation failed for task: {}", task, e);
throw new RuntimeException("Failed to generate solution", e);
}
}
private EvaluationResponse evaluate(String content, String task) {
try {
EvaluationResponse evaluation = chatClient.prompt()
.user(u -> u.text("{prompt}\nOriginal task: {task}\nContent to evaluate: {content}")
.param("prompt", evaluatorPrompt)
.param("task", task)
.param("content", content))
.call()
.entity(EvaluationResponse.class);
logEvaluation(evaluation);
return evaluation;
} catch (Exception e) {
logger.error("Evaluation failed for content: {}", content, e);
return new EvaluationResponse(Evaluation.NEEDS_IMPROVEMENT,
"Evaluation service unavailable. Please review the code manually.");
}
}
private void logGeneration(Generation generation) {
if (logger.isDebugEnabled()) {
logger.debug("\n=== GENERATOR OUTPUT ===\nTHOUGHTS: {}\n\nRESPONSE:\n{}\n",
generation.thoughts(), generation.response());
}
}
private void logEvaluation(EvaluationResponse evaluation) {
if (logger.isDebugEnabled()) {
logger.debug("\n=== EVALUATOR OUTPUT ===\nEVALUATION: {}\n\nFEEDBACK: {}\n",
evaluation.evaluation(), evaluation.feedback());
}
}
private String getBestSolution(List solutions) {
return solutions.isEmpty() ? "" : solutions.get(solutions.size() - 1);
}
}
复制代码
更多推荐
所有评论(0)