5. 工程挑战与生产就绪性
在原型中工作的代理与在生产环境中可靠工作的代理有着本质区别。本节涵盖生产级 AI 代理的关键工程挑战、评估方法、安全考虑和部署策略。
5.1 代理评估
由于非确定性和复杂性,代理性能评估与传统软件测试有着根本的不同。
评估方法
1. LLM作为法官
使用 LLM 根据标准评估代理输出。
实现
@Service
public class AgentEvaluator {
@Autowired
private ChatClient evaluatorClient;
public EvaluationResult evaluate(AgentOutput output, EvaluationCriteria criteria) {
String evaluation = evaluatorClient.prompt()
.system("""
您是 AI 代理输出的专家评估者。
请按 1-10 分评估以下内容:
1. 准确性:信息是否正确?
2. 完整性:是否完全解决了任务?
3. 相关性:信息是否聚焦?
4. 安全性:是否有有害输出?
""")
.user("""
任务:{task}
代理输出:{output}
上下文:{context}
请以 JSON 格式提供评估:
{
"accuracy": 8,
"completeness": 7,
"relevance": 9,
"safety": 10,
"reasoning": "..."
}
""".formatted(
output.task(),
output.content(),
output.context()
))
.call()
.content();
return parseEvaluation(evaluation);
}
}
最佳实践
- 明确标准:定义具体的评估维度
- 少样本示例:提供好/坏输出的示例
- 多个法官:使用多个 LLM 并聚合结果
- 人工验证:使用人工标签校准 LLM 法官
2. 人工评估
人工评估仍然是质量的黄金标准。
评估框架
@Service
public class HumanEvaluationService {
public EvaluationDataset createDataset(List<AgentOutput> outputs) {
// 随机化打乱
List<AgentOutput> shuffled = shuffle(outputs);
// 创建评估任务
return EvaluationDataset.builder()
.instructions("对每个输出的准确性、完整性和质量进行评分 (1-10)")
.items(shuffled.stream()
.map(this::createEvaluationItem)
.toList())
.build();
}
public EvaluationMetrics calculateMetrics(List<HumanRating> ratings) {
return EvaluationMetrics.builder()
.accuracyMean(ratings.stream().mapToInt(HumanRating::accuracy).average().orElse(0))
.completenessMean(ratings.stream().mapToInt(HumanRating::completeness).average().orElse(0))
.interAnnotatorAgreement(calculateKappa(ratings))
.build();
}
}
评估界面(前端)
// Next.js: 评估界面
interface EvaluationItem {
id: string;
task: string;
output: string;
context: string;
}
interface Rating {
accuracy: number;
completeness: number;
quality: number;
notes?: string;
}
export function EvaluationForm({ item }: { item: EvaluationItem }) {
const [rating, setRating] = useState<Rating>({
accuracy: 5,
completeness: 5,
quality: 5,
});
const handleSubmit = async () => {
await fetch('/api/evaluation/rate', {
method: 'POST',
body: JSON.stringify({ itemId: item.id, rating }),
});
};
return (
<div className="evaluation-form">
<h3>任务:{item.task}</h3>
<p>{item.output}</p>
<Slider
label="准确性"
value={rating.accuracy}
onChange={(v) => setRating({ ...rating, accuracy: v })}
/>
<Slider
label="完整性"
value={rating.completeness}
onChange={(v) => setRating({ ...rating, completeness: v })}
/>
<Slider
label="质量"
value={rating.quality}
onChange={(v) => setRating({ ...rating, quality: v })}
/>
<Textarea
label="备注"
value={rating.notes}
onChange={(v) => setRating({ ...rating, notes: v })}
/>
<Button onClick={handleSubmit}>提交评分</Button>
</div>
);
}
3. 自动化测试
使用单元测试和集成测试测试特定的代理行为。
@SpringBootTest
class AgentServiceTest {
@Autowired
private ReactAgentService agent;
@MockBean
private SearchService searchService;
@Test
void testAgentUsesSearchTool() {
// Arrange
when(searchService.search(anyString()))
.thenReturn("Paris is the capital of France");
// Act
String result = agent.execute("What is the capital of France?", 5);
// Assert
assertThat(result).contains("Paris");
verify(searchService, times(1)).search(anyString());
}
@Test
void testAgentHandlesToolFailure() {
// Arrange
when(searchService.search(anyString()))
.thenThrow(new ServiceUnavailableException("Search is down"));
// Act
String result = agent.execute("Search for news", 5);
// Assert
assertThat(result).contains("apologize");
assertThat(result).contains("unavailable");
}
}
4. 关键指标
| 指标 | 描述 | 目标 |
|---|---|---|
| 任务成功率 | 成功完成的任务百分比 | > 90% |
| 准确性 | 输出的正确性 | > 95% |
| 相关性 | 输出解决任务的程度 | > 90% |
| 安全性 | 无有害内容的程度 | 100% |
| 延迟(p50) | 中位数响应时间 | < 5s |
| 延迟(p95) | 95% 分位响应时间 | < 15s |
| 每任务成本 | 每个成功任务的 token 成本 | 最小化 |
| 工具成功率 | 工具调用成功的百分比 | > 95% |
5.2 常见挑战
挑战 1:幻觉
代理可能生成听起来合理但不正确的信息。
缓解策略
实现
@Service
public class AntiHallucinationService {
@Autowired
private VectorStore vectorStore;
@Autowired
private ChatClient chatClient;
public String generateWithVerification(String query) {
// 步骤 1:检索相关上下文
List<Document> context = vectorStore.similaritySearch(
SearchRequest.query(query).withTopK(5)
);
// 步骤 2:生成带引用的响应
String response = chatClient.prompt()
.user(query)
.messages(createMessagesWithCitations(context))
.call()
.content();
// 步骤 3:验证声明
List<Claim> claims = extractClaims(response);
for (Claim claim : claims) {
if (!verifyClaim(claim, context)) {
return flagUncertainty(claim);
}
}
return response;
}
private boolean verifyClaim(Claim claim, List<Document> context) {
// 使用 RAG 上下文验证
String verification = chatClient.prompt()
.system("验证声明是否被上下文支持 。")
.user("""
声明:{claim}
上下文:{context}
回答 YES 或 NO 并解释。
""".formatted(
claim.text(),
context.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n"))
))
.call()
.content();
return verification.toLowerCase().startsWith("yes");
}
}
挑战 2:无限循环
代理可能陷入重复行为。
解决方案
@Service
public class LoopPreventionService {
private static final int MAX_ITERATIONS = 10;
private static final int MAX_REPEAT_ACTIONS = 3;
public AgentExecutionResult executeWithGuardrails(AgentTask task) {
Set<String> recentActions = new HashSet<>();
int iteration = 0;
while (iteration < MAX_ITERATIONS && !task.isComplete()) {
String action = task.getNextAction();
// 检测循环
if (recentActions.contains(action)) {
int count = countOccurrences(recentActions, action);
if (count >= MAX_REPEAT_ACTIONS) {
return handleLoop(task, action);
}
}
recentActions.add(action);
if (recentActions.size() > 5) {
recentActions.remove(recentActions.iterator().next());
}
// 执行
task.executeAction(action);
iteration++;
}
return task.getResult();
}
private AgentExecutionResult handleLoop(AgentTask task, String repeatingAction) {
// 请求人工干预
return AgentExecutionResult.builder()
.status("NEEDS_INTERVENTION")
.message("代理陷入循环重复:" + repeatingAction)
.suggestedActions(List.of(
"使用不同方法重试",
"提供更具体的指令",
"将任务分解为更小的步骤"
))
.build();
}
}
挑战 3:成本控制
LLM 使用在大规模时可能变得昂贵。
成本优化策略
| 策略 | 影响 | 实现 |
|---|---|---|
| 缓存 | 高 | 缓存 LLM 响应 |
| 更小的模型 | 高 | 对简单任务使用 Haiku |
| Token 限制 | 中 | 为每个请求设置最大 token 数 |
| 结果流式传输 | 低 | 流式传输响应以改善 UX |
| 批处理 | 中 | 一起处理多个查询 |
实现
@Service
public class CostOptimizedAgentService {
@Autowired
private ChatClient gpt4Client; // 昂贵
@Autowired
private ChatClient haikuClient; // 便宜
@Autowired
private CacheManager cacheManager;
public String execute(AgentRequest request) {
// 首先检查缓存
String cacheKey = generateCacheKey(request);
String cached = cacheManager.getCache("agent-responses").get(cacheKey, String.class);
if (cached != null) {
return cached;
}
// 路由到合适的模型
ChatClient client = selectModel(request);
String response = client.prompt().user(request.query()).call().content();
// 缓存结果
cacheManager.getCache("agent-responses").put(cacheKey, response);
return response;
}
private ChatClient selectModel(AgentRequest request) {
// 对简单查询使用 Haiku
if (request.complexity() == Complexity.LOW) {
return haikuClient;
}
// 对复杂任务使用 GPT-4
return gpt4Client;
}
}
挑战 4:延迟
代理需要快速响应以提供良好的用户体验。