格式化
This commit is contained in:
parent
af6171f5fc
commit
e879784209
@ -3,9 +3,7 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\LLM\Qwen;
|
use App\LLM\Qwen;
|
||||||
use App\Models\Assistant;
|
|
||||||
use App\Models\Tool;
|
use App\Models\Tool;
|
||||||
use App\Repositories\LLM\AIMessage;
|
|
||||||
use App\Repositories\LLM\ChatEnum;
|
use App\Repositories\LLM\ChatEnum;
|
||||||
use App\Repositories\LLM\History;
|
use App\Repositories\LLM\History;
|
||||||
use App\Repositories\LLM\HumanMessage;
|
use App\Repositories\LLM\HumanMessage;
|
||||||
@ -30,6 +28,7 @@ class TestLLM extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
|
*
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
@ -45,12 +44,12 @@ public function handle()
|
|||||||
$llm->setHistory($history);
|
$llm->setHistory($history);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// var_dump($history->getMessages());
|
// var_dump($history->getMessages());
|
||||||
|
|
||||||
$q = $this->ask('请输入问题');
|
$q = $this->ask('请输入问题');
|
||||||
|
|
||||||
if (empty($q)) {
|
if (empty($q)) {
|
||||||
$q = "北京天气";
|
$q = '北京天气';
|
||||||
}
|
}
|
||||||
|
|
||||||
$history->addMessage(new HumanMessage($q));
|
$history->addMessage(new HumanMessage($q));
|
||||||
@ -60,12 +59,12 @@ public function handle()
|
|||||||
foreach ($s as $item) {
|
foreach ($s as $item) {
|
||||||
if ($item->role == ChatEnum::Tool) {
|
if ($item->role == ChatEnum::Tool) {
|
||||||
if ($item->processing) {
|
if ($item->processing) {
|
||||||
$this->info("正在执行: " . $item->content);
|
$this->info('正在执行: '.$item->content);
|
||||||
echo "\n";
|
echo "\n";
|
||||||
} else {
|
} else {
|
||||||
$this->info("执行结果: " . $item->content);
|
$this->info('执行结果: '.$item->content);
|
||||||
}
|
}
|
||||||
} else if ($item->role == ChatEnum::AssistantChunk) {
|
} elseif ($item->role == ChatEnum::AssistantChunk) {
|
||||||
echo $item->getLastAppend();
|
echo $item->getLastAppend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,11 +44,10 @@ public function store(Request $request)
|
|||||||
|
|
||||||
$json = Http::get($url);
|
$json = Http::get($url);
|
||||||
|
|
||||||
|
|
||||||
$tool = new Tool();
|
$tool = new Tool();
|
||||||
$tool = $tool->create([
|
$tool = $tool->create([
|
||||||
'name' => "",
|
'name' => '',
|
||||||
'description' => "",
|
'description' => '',
|
||||||
'discovery_url' => $url,
|
'discovery_url' => $url,
|
||||||
'api_key' => $request->input('api_key'),
|
'api_key' => $request->input('api_key'),
|
||||||
'user_id' => $request->user('api')->id,
|
'user_id' => $request->user('api')->id,
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\LLM;
|
namespace App\LLM;
|
||||||
|
|
||||||
use App\Repositories\LLM\History;
|
use App\Repositories\LLM\History;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
interface BaseLLM
|
interface BaseLLM
|
||||||
{
|
{
|
||||||
public function setHistory(History $history);
|
public function setHistory(History $history);
|
||||||
|
|
||||||
public function setTools(Collection $tools);
|
public function setTools(Collection $tools);
|
||||||
|
|
||||||
|
|
||||||
public function streamResponse();
|
public function streamResponse();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ class Qwen implements BaseLLM
|
|||||||
private array $tool_info = [];
|
private array $tool_info = [];
|
||||||
|
|
||||||
private Collection $tools;
|
private Collection $tools;
|
||||||
|
|
||||||
private array $tool_functions = [];
|
private array $tool_functions = [];
|
||||||
|
|
||||||
const END_OF_MESSAGE = "/\r\n\r\n|\n\n|\r\r/";
|
const END_OF_MESSAGE = "/\r\n\r\n|\n\n|\r\r/";
|
||||||
@ -69,17 +70,16 @@ public function streamResponse()
|
|||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
'Accept' => 'text/event-stream',
|
'Accept' => 'text/event-stream',
|
||||||
'Cache-Control' => 'no-cache',
|
'Cache-Control' => 'no-cache',
|
||||||
'Authorization' => 'Bearer ' . config('services.dashscope.api_key'),
|
'Authorization' => 'Bearer '.config('services.dashscope.api_key'),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$url = config('services.dashscope.api_base') . '/compatible-mode/v1/chat/completions';
|
$url = config('services.dashscope.api_base').'/compatible-mode/v1/chat/completions';
|
||||||
|
|
||||||
|
|
||||||
$this->request_again = true;
|
$this->request_again = true;
|
||||||
while ($this->request_again) {
|
while ($this->request_again) {
|
||||||
|
|
||||||
$ai_chunk_message = new AIChunkMessage("");
|
$ai_chunk_message = new AIChunkMessage('');
|
||||||
|
|
||||||
$request_body = [
|
$request_body = [
|
||||||
'model' => $this->model,
|
'model' => $this->model,
|
||||||
@ -97,7 +97,7 @@ public function streamResponse()
|
|||||||
|
|
||||||
$buffer = '';
|
$buffer = '';
|
||||||
|
|
||||||
while (!$body->eof()) {
|
while (! $body->eof()) {
|
||||||
$data = $body->read(1);
|
$data = $body->read(1);
|
||||||
|
|
||||||
$buffer .= $data;
|
$buffer .= $data;
|
||||||
@ -117,7 +117,6 @@ public function streamResponse()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (empty($d)) {
|
if (empty($d)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -129,7 +128,7 @@ public function streamResponse()
|
|||||||
$ai_chunk_message->processing = false;
|
$ai_chunk_message->processing = false;
|
||||||
$this->history->addMessage($ai_chunk_message->toAIMessage());
|
$this->history->addMessage($ai_chunk_message->toAIMessage());
|
||||||
break;
|
break;
|
||||||
// yield $ai_chunk_message;
|
// yield $ai_chunk_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
$delta = $event['choices'][0]['delta'];
|
$delta = $event['choices'][0]['delta'];
|
||||||
@ -147,14 +146,13 @@ public function streamResponse()
|
|||||||
|
|
||||||
$r = $this->callTool($this->tool_info['function']['name'], $info);
|
$r = $this->callTool($this->tool_info['function']['name'], $info);
|
||||||
|
|
||||||
|
// $tool_response = [
|
||||||
|
// 'name' => $this->tool_info['function']['name'],
|
||||||
|
// 'role' => 'tool',
|
||||||
|
// 'content' => $r,
|
||||||
|
// ];
|
||||||
|
|
||||||
// $tool_response = [
|
$tool_call_message = new AIToolCallMessage(content: '');
|
||||||
// 'name' => $this->tool_info['function']['name'],
|
|
||||||
// 'role' => 'tool',
|
|
||||||
// 'content' => $r,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
$tool_call_message = new AIToolCallMessage(content: "");
|
|
||||||
$tool_call_message->tool_calls = [
|
$tool_call_message->tool_calls = [
|
||||||
$this->tool_info,
|
$this->tool_info,
|
||||||
];
|
];
|
||||||
@ -167,15 +165,14 @@ public function streamResponse()
|
|||||||
|
|
||||||
yield $tool_call_message;
|
yield $tool_call_message;
|
||||||
yield $tool_response_message;
|
yield $tool_response_message;
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// $this->history[] = $tool_response;
|
// $this->history[] = $tool_response;
|
||||||
|
|
||||||
// yield new ToolResponseMessage(
|
|
||||||
// content: $tool_response_message->content,
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
// yield new ToolResponseMessage(
|
||||||
|
// content: $tool_response_message->content,
|
||||||
|
// );
|
||||||
|
|
||||||
// 清空参数,以备二次调用
|
// 清空参数,以备二次调用
|
||||||
$this->clearToolInfo();
|
$this->clearToolInfo();
|
||||||
@ -202,7 +199,7 @@ public function streamResponse()
|
|||||||
$this->tool_info['function']['arguments'] .= $call_info['function']['arguments'];
|
$this->tool_info['function']['arguments'] .= $call_info['function']['arguments'];
|
||||||
}
|
}
|
||||||
} elseif (empty($delta['choices'][0]['finish_reason'])) {
|
} elseif (empty($delta['choices'][0]['finish_reason'])) {
|
||||||
if (!empty($delta['content'])) {
|
if (! empty($delta['content'])) {
|
||||||
$ai_chunk_message->append($delta['content']);
|
$ai_chunk_message->append($delta['content']);
|
||||||
$ai_chunk_message->processing = true;
|
$ai_chunk_message->processing = true;
|
||||||
|
|
||||||
@ -214,12 +211,10 @@ public function streamResponse()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$buffer = '';
|
$buffer = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -240,7 +235,6 @@ private function callTool($tool_name, $args): string
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "[Hint] 没有找到对应的工具 " . $tool_name . ',你确定是这个吗?';
|
return '[Hint] 没有找到对应的工具 '.$tool_name.',你确定是这个吗?';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public function callTool(string $function_name, $parameters = []): FunctionCall
|
|||||||
$r->name = $function_name;
|
$r->name = $function_name;
|
||||||
$r->parameters = $parameters;
|
$r->parameters = $parameters;
|
||||||
|
|
||||||
if (!$http->ok()) {
|
if (! $http->ok()) {
|
||||||
$r->success = false;
|
$r->success = false;
|
||||||
$r->result = "[Error] 我们的服务器与工具 $function_name 通讯失败";
|
$r->result = "[Error] 我们的服务器与工具 $function_name 通讯失败";
|
||||||
}
|
}
|
||||||
@ -44,9 +44,10 @@ public function callTool(string $function_name, $parameters = []): FunctionCall
|
|||||||
$d = $http->json();
|
$d = $http->json();
|
||||||
|
|
||||||
// 必须有 success 和 message 两个
|
// 必须有 success 和 message 两个
|
||||||
if (!isset($d['success']) || !isset($d['message'])) {
|
if (! isset($d['success']) || ! isset($d['message'])) {
|
||||||
$r->success = false;
|
$r->success = false;
|
||||||
$r->result = "[Error] 和 工具 $function_name 通讯失败,返回数据格式错误。";
|
$r->result = "[Error] 和 工具 $function_name 通讯失败,返回数据格式错误。";
|
||||||
|
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
class AIChunkMessage extends BaseMessage
|
class AIChunkMessage extends BaseMessage
|
||||||
{
|
{
|
||||||
public ChatEnum $role = ChatEnum::AssistantChunk;
|
public ChatEnum $role = ChatEnum::AssistantChunk;
|
||||||
protected string $last_append = "";
|
|
||||||
|
protected string $last_append = '';
|
||||||
|
|
||||||
public function toAIMessage(): AIMessage
|
public function toAIMessage(): AIMessage
|
||||||
{
|
{
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
class AIToolCallMessage extends BaseMessage
|
class AIToolCallMessage extends BaseMessage
|
||||||
{
|
{
|
||||||
|
|
||||||
public ChatEnum $role = ChatEnum::Assistant;
|
public ChatEnum $role = ChatEnum::Assistant;
|
||||||
|
|
||||||
public array $tool_calls;
|
public array $tool_calls;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
class BaseMessage
|
class BaseMessage
|
||||||
{
|
{
|
||||||
public string $content;
|
public string $content;
|
||||||
|
|
||||||
public bool $processing = false;
|
public bool $processing = false;
|
||||||
|
|
||||||
public function __construct(string $content)
|
public function __construct(string $content)
|
||||||
@ -12,7 +13,6 @@ public function __construct(string $content)
|
|||||||
$this->content = $content;
|
$this->content = $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function append(string $content): void
|
public function append(string $content): void
|
||||||
{
|
{
|
||||||
$this->content .= $content;
|
$this->content .= $content;
|
||||||
@ -27,5 +27,4 @@ public function __toString(): string
|
|||||||
{
|
{
|
||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ public function getForApi(): array
|
|||||||
{
|
{
|
||||||
$history = [];
|
$history = [];
|
||||||
|
|
||||||
|
|
||||||
foreach ($this->history as $h) {
|
foreach ($this->history as $h) {
|
||||||
|
|
||||||
$a = [
|
$a = [
|
||||||
@ -47,6 +46,4 @@ public function getForApi(): array
|
|||||||
|
|
||||||
return $history;
|
return $history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,4 @@
|
|||||||
class HumanMessage extends BaseMessage
|
class HumanMessage extends BaseMessage
|
||||||
{
|
{
|
||||||
public ChatEnum $role = ChatEnum::Human;
|
public ChatEnum $role = ChatEnum::Human;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Repositories\LLM;
|
namespace App\Repositories\LLM;
|
||||||
|
|
||||||
class ToolMessage extends BaseMessage
|
class ToolMessage extends BaseMessage
|
||||||
{
|
{
|
||||||
public ChatEnum $role = ChatEnum::Tool;
|
public ChatEnum $role = ChatEnum::Tool;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Repositories\LLM;
|
namespace App\Repositories\LLM;
|
||||||
|
|
||||||
class ToolRequestMessage extends BaseMessage
|
class ToolRequestMessage extends BaseMessage
|
||||||
{
|
{
|
||||||
public ChatEnum $role = ChatEnum::Tool;
|
public ChatEnum $role = ChatEnum::Tool;
|
||||||
|
|
||||||
public bool $processing = true;
|
public bool $processing = true;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ class ToolResponseMessage extends BaseMessage
|
|||||||
public ChatEnum $role = ChatEnum::Tool;
|
public ChatEnum $role = ChatEnum::Tool;
|
||||||
|
|
||||||
public bool $requesting = false;
|
public bool $requesting = false;
|
||||||
public string $name;
|
|
||||||
|
|
||||||
|
public string $name;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ class Tool
|
|||||||
public string $callback_url;
|
public string $callback_url;
|
||||||
|
|
||||||
public string $description;
|
public string $description;
|
||||||
|
|
||||||
public int $tool_id;
|
public int $tool_id;
|
||||||
|
|
||||||
public array $tool_functions;
|
public array $tool_functions;
|
||||||
|
@ -16,6 +16,7 @@ class ToolFunction
|
|||||||
protected array $data;
|
protected array $data;
|
||||||
|
|
||||||
public array $required;
|
public array $required;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*
|
*
|
||||||
@ -33,7 +34,7 @@ public function __construct(array $data)
|
|||||||
private function parse(): void
|
private function parse(): void
|
||||||
{
|
{
|
||||||
$random_str = Str::random(config('settings.function_call.random_prefix_length'));
|
$random_str = Str::random(config('settings.function_call.random_prefix_length'));
|
||||||
$this->name = $random_str . '_' . $this->data['name'];
|
$this->name = $random_str.'_'.$this->data['name'];
|
||||||
$this->description = $this->data['description'];
|
$this->description = $this->data['description'];
|
||||||
|
|
||||||
// 如果 parameters 不为空,则验证
|
// 如果 parameters 不为空,则验证
|
||||||
|
@ -40,5 +40,4 @@
|
|||||||
'api_base' => env('DASHSCOPE_API_BASE', 'https://dashscope.aliyuncs.com'),
|
'api_base' => env('DASHSCOPE_API_BASE', 'https://dashscope.aliyuncs.com'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
return [
|
return [
|
||||||
'function_call' => [
|
'function_call' => [
|
||||||
// 防止命名冲突的随机长度,如果你更改了它,则需要更新全部函数的 name
|
// 防止命名冲突的随机长度,如果你更改了它,则需要更新全部函数的 name
|
||||||
'random_prefix_length' => 8
|
'random_prefix_length' => 8,
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
Loading…
Reference in New Issue
Block a user