Appearance
Agent框架实践
PHP开发者也能构建强大的Agent系统
PHP Agent开发生态
虽然主流Agent框架(LangChain、AutoGen、CrewAI)都是Python编写,但PHP开发者完全可以构建功能强大的Agent系统。
PHP Agent开发方案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 原生方案 框架集成 混合架构 │
│ ──────── ──────── ──────── │
│ • OpenAI PHP Client • Laravel AI • PHP + Python │
│ • Anthropic PHP • Symfony Bundle • 微服务架构 │
│ • 自定义实现 • Lumen API • API网关 │
│ │
│ 核心能力 │
│ ──────── │
│ • Function Calling │
│ • 多Agent协作 │
│ • RAG实现 │
│ • 工具链集成 │
│ │
└─────────────────────────────────────────────────────────────┘方案对比
| 方案 | 复杂度 | 灵活性 | 适用场景 |
|---|---|---|---|
| 原生实现 | 中等 | 高 | 定制化需求、学习理解 |
| Laravel集成 | 低 | 中 | Web应用、快速开发 |
| 混合架构 | 高 | 高 | 企业级应用、复杂系统 |
环境准备
安装依赖
bash
composer require openai-php/client
composer require guzzlehttp/guzzle
composer require psr/log基础配置
php
<?php
// 返回配置数组
return [
// OpenAI配置
'openai' => [
// API密钥
'api_key' => env('OPENAI_API_KEY'),
// 模型选择
'model' => env('OPENAI_MODEL', 'gpt-4'),
// 最大token数
'max_tokens' => env('OPENAI_MAX_TOKENS', 4096),
// 温度参数
'temperature' => env('OPENAI_TEMPERATURE', 0.7),
],
// Anthropic配置
'anthropic' => [
// API密钥
'api_key' => env('ANTHROPIC_API_KEY'),
// 模型选择
'model' => env('ANTHROPIC_MODEL', 'claude-3-opus-20240229'),
],
];原生Agent实现
核心Agent类
php
<?php
namespace App\Agent;
use OpenAI\Client;
use OpenAI\Responses\Chat\CreateResponse;
class Agent
{
protected Client $client;
protected array $tools = [];
protected array $messages = [];
protected int $maxIterations = 10;
protected string $systemPrompt = '';
public function __construct(Client $client)
{
$this->client = $client;
}
public function setSystemPrompt(string $prompt): self
{
$this->systemPrompt = $prompt;
return $this;
}
public function addTool(Tool $tool): self
{
$this->tools[$tool->getName()] = $tool;
return $this;
}
public function run(string $userInput): string
{
$this->messages = [];
if ($this->systemPrompt) {
$this->messages[] = [
'role' => 'system',
'content' => $this->systemPrompt
];
}
$this->messages[] = [
'role' => 'user',
'content' => $userInput
];
for ($i = 0; $i < $this->maxIterations; $i++) {
$response = $this->callLLM();
$message = $response->choices[0]->message;
if (!$this->hasToolCalls($message)) {
return $message->content;
}
$this->messages[] = $message->toArray();
foreach ($message->toolCalls as $toolCall) {
$result = $this->executeToolCall($toolCall);
$this->messages[] = [
'role' => 'tool',
'tool_call_id' => $toolCall->id,
'content' => $result
];
}
}
return '达到最大迭代次数,任务未完成';
}
protected function callLLM(): CreateResponse
{
$params = [
'model' => 'gpt-4',
'messages' => $this->messages,
];
if (!empty($this->tools)) {
$params['tools'] = $this->getToolDefinitions();
$params['tool_choice'] = 'auto';
}
return $this->client->chat()->create($params);
}
protected function hasToolCalls($message): bool
{
return isset($message->toolCalls) && count($message->toolCalls) > 0;
}
protected function executeToolCall($toolCall): string
{
$toolName = $toolCall->function->name;
$arguments = json_decode($toolCall->function->arguments, true);
if (!isset($this->tools[$toolName])) {
return json_encode(['error' => "Unknown tool: {$toolName}"]);
}
return $this->tools[$toolName]->execute($arguments);
}
protected function getToolDefinitions(): array
{
return array_map(
fn(Tool $tool) => $tool->getDefinition(),
array_values($this->tools)
);
}
}工具基类
php
<?php
namespace App\Agent;
abstract class Tool
{
protected string $name;
protected string $description;
protected array $parameters = [];
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function getDefinition(): array
{
return [
'type' => 'function',
'function' => [
'name' => $this->name,
'description' => $this->description,
'parameters' => $this->parameters
]
];
}
abstract public function execute(array $arguments): string;
}具体工具实现
php
<?php
namespace App\Agent\Tools;
use App\Agent\Tool;
class WeatherTool extends Tool
{
protected string $name = 'get_weather';
protected string $description = '获取指定城市的天气信息';
protected array $parameters = [
'type' => 'object',
'properties' => [
'city' => [
'type' => 'string',
'description' => '城市名称,如:北京、上海'
],
'unit' => [
'type' => 'string',
'enum' => ['celsius', 'fahrenheit'],
'description' => '温度单位'
]
],
'required' => ['city']
];
public function execute(array $arguments): string
{
$city = $arguments['city'];
$unit = $arguments['unit'] ?? 'celsius';
$weatherData = $this->fetchWeather($city);
return json_encode([
'city' => $city,
'temperature' => $weatherData['temp'],
'condition' => $weatherData['condition'],
'unit' => $unit
], JSON_UNESCAPED_UNICODE);
}
private function fetchWeather(string $city): array
{
$data = [
'北京' => ['temp' => '20-28', 'condition' => '晴天'],
'上海' => ['temp' => '22-30', 'condition' => '多云'],
];
return $data[$city] ?? ['temp' => '未知', 'condition' => '未知'];
}
}
class SearchTool extends Tool
{
protected string $name = 'search_web';
protected string $description = '搜索网络获取信息';
protected array $parameters = [
'type' => 'object',
'properties' => [
'query' => [
'type' => 'string',
'description' => '搜索关键词'
],
'num_results' => [
'type' => 'integer',
'description' => '返回结果数量',
'default' => 5
]
],
'required' => ['query']
];
public function execute(array $arguments): string
{
$query = $arguments['query'];
$numResults = $arguments['num_results'] ?? 5;
$results = $this->search($query, $numResults);
return json_encode([
'query' => $query,
'results' => $results
], JSON_UNESCAPED_UNICODE);
}
private function search(string $query, int $numResults): array
{
return array_map(
fn($i) => "结果{$i}: {$query}相关内容",
range(1, $numResults)
);
}
}
class CalculatorTool extends Tool
{
protected string $name = 'calculate';
protected string $description = '执行数学计算';
protected array $parameters = [
'type' => 'object',
'properties' => [
'expression' => [
'type' => 'string',
'description' => '数学表达式,如:2+2、10*5'
]
],
'required' => ['expression']
];
public function execute(array $arguments): string
{
$expression = $arguments['expression'];
try {
$result = $this->evaluate($expression);
return json_encode([
'expression' => $expression,
'result' => $result
]);
} catch (\Exception $e) {
return json_encode([
'error' => '计算错误: ' . $e->getMessage()
]);
}
}
private function evaluate(string $expression): float
{
if (!preg_match('/^[\d\s\+\-\*\/\(\)\.]+$/', $expression)) {
throw new \InvalidArgumentException('Invalid expression');
}
return eval("return {$expression};");
}
}使用示例
php
<?php
use OpenAI;
use App\Agent\Agent;
use App\Agent\Tools\WeatherTool;
use App\Agent\Tools\SearchTool;
use App\Agent\Tools\CalculatorTool;
$client = OpenAI::factory()
->withApiKey($_ENV['OPENAI_API_KEY'])
->make();
$agent = new Agent($client);
$agent->setSystemPrompt('你是一个智能助手,可以使用工具帮助用户解决问题。')
->addTool(new WeatherTool())
->addTool(new SearchTool())
->addTool(new CalculatorTool());
echo $agent->run("北京今天天气怎么样?");
echo $agent->run("帮我计算 123 * 456");
echo $agent->run("搜索一下PHP Agent开发的相关信息");ReAct Agent实现
ReAct模式
php
<?php
namespace App\Agent;
class ReActAgent extends Agent
{
protected string $reactPrompt = <<<PROMPT
你是一个智能Agent,使用ReAct模式完成任务。
你可以使用的工具:
{tools}
使用以下格式:
Thought: 你的思考过程
Action: {"tool": "工具名", "params": {参数}}
Observation: 工具执行结果
... (重复 Thought/Action/Observation)
Thought: 我知道最终答案了
Final Answer: 最终答案
开始!
PROMPT;
public function run(string $userInput): string
{
$this->messages = [];
$toolDescriptions = $this->getToolDescriptions();
$systemPrompt = str_replace('{tools}', $toolDescriptions, $this->reactPrompt);
$this->messages[] = [
'role' => 'system',
'content' => $systemPrompt
];
$this->messages[] = [
'role' => 'user',
'content' => $userInput
];
for ($i = 0; $i < $this->maxIterations; $i++) {
$response = $this->callLLM();
$content = $response->choices[0]->message->content;
if ($this->isFinalAnswer($content)) {
return $this->extractFinalAnswer($content);
}
$action = $this->parseAction($content);
if ($action) {
$observation = $this->executeAction($action);
$this->messages[] = [
'role' => 'assistant',
'content' => $content
];
$this->messages[] = [
'role' => 'user',
'content' => "Observation: {$observation}"
];
}
}
return '达到最大迭代次数,任务未完成';
}
protected function getToolDescriptions(): string
{
$descriptions = [];
foreach ($this->tools as $tool) {
$descriptions[] = "- {$tool->getName()}: {$tool->getDescription()}";
}
return implode("\n", $descriptions);
}
protected function isFinalAnswer(string $content): bool
{
return str_contains($content, 'Final Answer:');
}
protected function extractFinalAnswer(string $content): string
{
if (preg_match('/Final Answer:\s*(.+)/s', $content, $matches)) {
return trim($matches[1]);
}
return $content;
}
protected function parseAction(string $content): ?array
{
if (preg_match('/Action:\s*(\{.+\})/s', $content, $matches)) {
return json_decode($matches[1], true);
}
return null;
}
protected function executeAction(array $action): string
{
$toolName = $action['tool'] ?? '';
$params = $action['params'] ?? [];
if (!isset($this->tools[$toolName])) {
return "Unknown tool: {$toolName}";
}
return $this->tools[$toolName]->execute($params);
}
}Laravel集成
服务提供者
php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use OpenAI\Client;
use OpenAI;
class AgentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(Client::class, function () {
return OpenAI::factory()
->withApiKey(config('services.openai.api_key'))
->make();
});
$this->app->singleton(AgentManager::class, function ($app) {
return new AgentManager($app->make(Client::class));
});
}
public function boot(): void
{
$this->publishes([
__DIR__ . '/../config/agent.php' => config_path('agent.php'),
]);
}
}Agent管理器
php
<?php
namespace App\Agent;
class AgentManager
{
private Client $client;
private array $agents = [];
public function __construct(Client $client)
{
$this->client = $client;
}
public function create(string $name, array $config = []): Agent
{
$agent = new Agent($this->client);
if (isset($config['system_prompt'])) {
$agent->setSystemPrompt($config['system_prompt']);
}
foreach ($config['tools'] ?? [] as $toolClass) {
$agent->addTool(app($toolClass));
}
$this->agents[$name] = $agent;
return $agent;
}
public function get(string $name): ?Agent
{
return $this->agents[$name] ?? null;
}
}Laravel控制器
php
<?php
namespace App\Http\Controllers;
use App\Agent\AgentManager;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class AgentController extends Controller
{
private AgentManager $agentManager;
public function __construct(AgentManager $agentManager)
{
$this->agentManager = $agentManager;
}
public function chat(Request $request): JsonResponse
{
$request->validate([
'message' => 'required|string',
'agent' => 'nullable|string'
]);
$agentName = $request->input('agent', 'default');
$agent = $this->agentManager->get($agentName);
if (!$agent) {
return response()->json([
'error' => "Agent not found: {$agentName}"
], 404);
}
$result = $agent->run($request->input('message'));
return response()->json([
'response' => $result
]);
}
public function createAgent(Request $request): JsonResponse
{
$request->validate([
'name' => 'required|string',
'system_prompt' => 'nullable|string',
'tools' => 'nullable|array'
]);
$agent = $this->agentManager->create($request->input('name'), [
'system_prompt' => $request->input('system_prompt'),
'tools' => $request->input('tools', [])
]);
return response()->json([
'message' => 'Agent created successfully',
'agent' => $request->input('name')
]);
}
}路由配置
php
<?php
use App\Http\Controllers\AgentController;
Route::prefix('api/agent')->group(function () {
Route::post('/chat', [AgentController::class, 'chat']);
Route::post('/create', [AgentController::class, 'createAgent']);
});多Agent协作实现
协调器
php
<?php
namespace App\Agent;
class AgentOrchestrator
{
private array $agents = [];
private array $workflow = [];
public function addAgent(string $name, Agent $agent): self
{
$this->agents[$name] = $agent;
return $this;
}
public function defineWorkflow(array $steps): self
{
$this->workflow = $steps;
return $this;
}
public function execute(string $input): array
{
$context = ['input' => $input];
$results = [];
foreach ($this->workflow as $step) {
$agentName = $step['agent'];
$promptTemplate = $step['prompt'];
$prompt = $this->buildPrompt($promptTemplate, $context);
$agent = $this->agents[$agentName];
$result = $agent->run($prompt);
$context[$agentName] = $result;
$results[$agentName] = $result;
}
return $results;
}
private function buildPrompt(string $template, array $context): string
{
$prompt = $template;
foreach ($context as $key => $value) {
$prompt = str_replace("{{$key}}", $value, $prompt);
}
return $prompt;
}
}研究团队示例
php
<?php
use App\Agent\Agent;
use App\Agent\AgentOrchestrator;
use App\Agent\Tools\SearchTool;
$client = OpenAI::factory()
->withApiKey($_ENV['OPENAI_API_KEY'])
->make();
$researcher = new Agent($client);
$researcher->setSystemPrompt('你是一个研究专家,负责收集信息。')
->addTool(new SearchTool());
$analyst = new Agent($client);
$analyst->setSystemPrompt('你是一个分析专家,负责分析数据。');
$writer = new Agent($client);
$writer->setSystemPrompt('你是一个写作专家,负责撰写报告。');
$orchestrator = new AgentOrchestrator();
$orchestrator->addAgent('researcher', $researcher)
->addAgent('analyst', $analyst)
->addAgent('writer', $writer)
->defineWorkflow([
[
'agent' => 'researcher',
'prompt' => '请研究以下主题:{input}'
],
[
'agent' => 'analyst',
'prompt' => '请分析以下研究结果:{researcher}'
],
[
'agent' => 'writer',
'prompt' => '请根据以下分析撰写报告:{analyst}'
]
]);
$results = $orchestrator->execute('AI Agent的发展趋势');
echo $results['writer'];记忆系统实现
会话记忆
php
<?php
namespace App\Agent\Memory;
class SessionMemory
{
private array $messages = [];
private int $maxMessages = 100;
public function add(string $role, string $content): void
{
$this->messages[] = [
'role' => $role,
'content' => $content,
'timestamp' => time()
];
if (count($this->messages) > $this->maxMessages) {
$this->messages = array_slice($this->messages, -$this->maxMessages);
}
}
public function getMessages(): array
{
return $this->messages;
}
public function getRecentMessages(int $count = 10): array
{
return array_slice($this->messages, -$count);
}
public function clear(): void
{
$this->messages = [];
}
public function getContext(): string
{
$lines = [];
foreach ($this->messages as $msg) {
$lines[] = "{$msg['role']}: {$msg['content']}";
}
return implode("\n", $lines);
}
}持久化记忆
php
<?php
namespace App\Agent\Memory;
use Illuminate\Support\Facades\Cache;
class PersistentMemory
{
private string $sessionId;
private int $ttl = 3600;
public function __construct(string $sessionId)
{
$this->sessionId = $sessionId;
}
public function remember(string $key, mixed $value): void
{
$data = $this->load();
$data[$key] = [
'value' => $value,
'timestamp' => time()
];
$this->save($data);
}
public function recall(string $key): mixed
{
$data = $this->load();
return $data[$key]['value'] ?? null;
}
public function forget(string $key): void
{
$data = $this->load();
unset($data[$key]);
$this->save($data);
}
public function all(): array
{
return $this->load();
}
private function load(): array
{
return Cache::get($this->getCacheKey(), []);
}
private function save(array $data): void
{
Cache::put($this->getCacheKey(), $data, $this->ttl);
}
private function getCacheKey(): string
{
return "agent_memory:{$this->sessionId}";
}
}实战案例
智能客服Agent
php
<?php
namespace App\Agents;
use App\Agent\Agent;
use App\Agent\Tools\Tool;
class CustomerServiceAgent extends Agent
{
protected string $systemPrompt = <<<PROMPT
你是一个专业的客服代表,负责回答用户问题。
你可以使用的工具:
- query_order: 查询订单状态
- create_ticket: 创建工单
- search_faq: 搜索常见问题
请友好、专业地回答用户问题。
PROMPT;
public function __construct($client)
{
parent::__construct($client);
$this->addTool(new class extends Tool {
protected string $name = 'query_order';
protected string $description = '查询订单状态';
protected array $parameters = [
'type' => 'object',
'properties' => [
'order_id' => [
'type' => 'string',
'description' => '订单号'
]
],
'required' => ['order_id']
];
public function execute(array $arguments): string
{
return json_encode([
'order_id' => $arguments['order_id'],
'status' => '已发货',
'tracking' => 'SF1234567890'
]);
}
});
$this->addTool(new class extends Tool {
protected string $name = 'create_ticket';
protected string $description = '创建工单';
protected array $parameters = [
'type' => 'object',
'properties' => [
'title' => ['type' => 'string'],
'description' => ['type' => 'string'],
'priority' => [
'type' => 'string',
'enum' => ['low', 'medium', 'high']
]
],
'required' => ['title', 'description']
];
public function execute(array $arguments): string
{
return json_encode([
'ticket_id' => 'TKT' . time(),
'status' => 'created'
]);
}
});
}
}数据分析Agent
php
<?php
namespace App\Agents;
use App\Agent\Agent;
use App\Agent\Tools\Tool;
class DataAnalysisAgent extends Agent
{
protected string $systemPrompt = <<<PROMPT
你是一个数据分析专家,可以帮助用户分析数据。
你可以使用的工具:
- query_database: 执行SQL查询
- calculate_statistics: 计算统计指标
- generate_chart: 生成图表
请提供专业的数据分析建议。
PROMPT;
public function __construct($client)
{
parent::__construct($client);
$this->addTool(new class extends Tool {
protected string $name = 'query_database';
protected string $description = '执行SQL查询(只允许SELECT)';
protected array $parameters = [
'type' => 'object',
'properties' => [
'sql' => [
'type' => 'string',
'description' => 'SQL查询语句'
]
],
'required' => ['sql']
];
public function execute(array $arguments): string
{
$sql = $arguments['sql'];
if (!str_starts_with(strtolower(trim($sql)), 'select')) {
return json_encode(['error' => '只允许SELECT查询']);
}
return json_encode([
'data' => [
['id' => 1, 'name' => 'Product A', 'sales' => 100],
['id' => 2, 'name' => 'Product B', 'sales' => 200],
]
]);
}
});
$this->addTool(new class extends Tool {
protected string $name = 'calculate_statistics';
protected string $description = '计算统计指标';
protected array $parameters = [
'type' => 'object',
'properties' => [
'data' => [
'type' => 'array',
'description' => '数据数组'
],
'metrics' => [
'type' => 'array',
'items' => [
'type' => 'string',
'enum' => ['mean', 'median', 'std', 'min', 'max']
]
]
],
'required' => ['data', 'metrics']
];
public function execute(array $arguments): string
{
$data = $arguments['data'];
$metrics = $arguments['metrics'];
$results = [];
foreach ($metrics as $metric) {
$results[$metric] = match($metric) {
'mean' => array_sum($data) / count($data),
'min' => min($data),
'max' => max($data),
default => null
};
}
return json_encode($results);
}
});
}
}性能优化
缓存策略
php
<?php
namespace App\Agent;
use Illuminate\Support\Facades\Cache;
class CachedAgent extends Agent
{
private int $cacheTtl = 3600;
public function run(string $userInput): string
{
$cacheKey = $this->generateCacheKey($userInput);
return Cache::remember($cacheKey, $this->cacheTtl, function () use ($userInput) {
return parent::run($userInput);
});
}
private function generateCacheKey(string $input): string
{
$context = md5(json_encode($this->messages));
return "agent:response:" . md5($input . $context);
}
}并行执行
php
<?php
namespace App\Agent;
use React\Promise\Promise;
class ParallelAgentExecutor
{
public function executeMultiple(array $agents, string $input): array
{
$results = [];
foreach ($agents as $name => $agent) {
$results[$name] = $agent->run($input);
}
return $results;
}
public function executeAsync(Agent $agent, string $input): Promise
{
return new Promise(function ($resolve) use ($agent, $input) {
$result = $agent->run($input);
$resolve($result);
});
}
}调试与监控
日志记录
php
<?php
namespace App\Agent;
use Psr\Log\LoggerInterface;
class LoggedAgent extends Agent
{
private LoggerInterface $logger;
public function __construct($client, LoggerInterface $logger)
{
parent::__construct($client);
$this->logger = $logger;
}
public function run(string $userInput): string
{
$this->logger->info('Agent started', ['input' => $userInput]);
$startTime = microtime(true);
try {
$result = parent::run($userInput);
$this->logger->info('Agent completed', [
'result' => substr($result, 0, 200),
'duration' => microtime(true) - $startTime
]);
return $result;
} catch (\Exception $e) {
$this->logger->error('Agent failed', [
'error' => $e->getMessage(),
'input' => $userInput
]);
throw $e;
}
}
}最佳实践
开发建议
1. 工具设计原则
────────────────────────────
• 单一职责:每个工具只做一件事
• 描述清晰:让LLM理解工具用途
• 参数验证:确保输入合法
• 错误处理:返回有意义的错误信息
2. 安全考虑
────────────────────────────
• 限制工具权限
• 验证所有输入
• 敏感信息保护
• 操作审计日志
3. 性能优化
────────────────────────────
• 使用缓存减少API调用
• 并行执行独立任务
• 控制上下文长度
• 选择合适的模型
4. 错误处理
────────────────────────────
• 重试机制
• 降级策略
• 用户友好提示
• 详细日志记录学习检验
概念理解
- PHP实现Agent的核心组件有哪些?
- 如何设计一个可扩展的工具系统?
- 如何实现多Agent协作?
实践任务
- 实现一个支持天气查询和计算的Agent
- 使用Laravel构建一个Agent API服务
- 实现一个简单的多Agent协作系统
下一步学习
💡 记住:PHP完全可以构建强大的Agent系统,关键是理解核心原理并合理设计架构。
