Add conditional web tools to LLM agent
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { AppConfig } from "../config.js";
|
||||
import type { Logger } from "../logger.js";
|
||||
import { webFetch, webSearch } from "./web-tools.js";
|
||||
|
||||
interface OllamaChatMessage {
|
||||
role: "system" | "user" | "assistant";
|
||||
@@ -42,7 +43,7 @@ interface OllamaToolResultMessage {
|
||||
}
|
||||
|
||||
const SYSTEM_PROMPT =
|
||||
"너는 한국어로 짧고 자연스럽게 답하는 로컬 음성 비서다. 사용자의 말에 바로 답하고, 군더더기 없는 1~3문장으로 답해라. 정확한 시간, 설정 확인, 계산이 필요하면 도구를 우선 사용해라. 너는 도구 호출 루프 안에 있으며 필요하면 여러 번 도구를 호출할 수 있다.";
|
||||
"너는 한국어로 짧고 자연스럽게 답하는 로컬 음성 비서다. 사용자의 말에 바로 답하고, 군더더기 없는 1~3문장으로 답해라. 정확한 시간, 설정 확인, 계산이 필요하면 도구를 우선 사용해라. 최신 정보, 오늘/최근 정보, 뉴스, 검색 요청, 사실 확인, 외부 웹페이지 내용이 필요한 경우에만 web_search 와 fetch_url 을 사용해라. 내부 지식만으로 충분한 일반 대화에는 웹 도구를 쓰지 마라. 너는 도구 호출 루프 안에 있으며 필요하면 여러 번 도구를 호출할 수 있다.";
|
||||
|
||||
const TOOL_DEFINITIONS: OllamaToolDefinition[] = [
|
||||
{
|
||||
@@ -95,6 +96,48 @@ const TOOL_DEFINITIONS: OllamaToolDefinition[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "web_search",
|
||||
description: "웹 검색 결과 제목, URL, 요약을 가져온다. 최신 정보, 뉴스, 사실 확인이 필요할 때만 사용한다.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
required: ["query"],
|
||||
properties: {
|
||||
query: {
|
||||
type: "string",
|
||||
description: "검색어",
|
||||
},
|
||||
max_results: {
|
||||
type: "number",
|
||||
description: "가져올 최대 결과 수. 보통 3~5",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "fetch_url",
|
||||
description: "주어진 URL의 페이지 제목과 본문 텍스트를 읽어온다. 검색 결과 상세 확인에 사용한다.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
required: ["url"],
|
||||
properties: {
|
||||
url: {
|
||||
type: "string",
|
||||
description: "http 또는 https URL",
|
||||
},
|
||||
max_chars: {
|
||||
type: "number",
|
||||
description: "본문에서 가져올 최대 글자 수",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export class OllamaLlmService {
|
||||
@@ -159,7 +202,7 @@ export class OllamaLlmService {
|
||||
}
|
||||
|
||||
for (const call of toolCalls) {
|
||||
const result = this.executeTool(call);
|
||||
const result = await this.executeTool(call);
|
||||
this.logger.info("LLM tool call", {
|
||||
name: call.function.name,
|
||||
arguments: call.function.arguments,
|
||||
@@ -213,7 +256,7 @@ export class OllamaLlmService {
|
||||
};
|
||||
}
|
||||
|
||||
private executeTool(call: OllamaToolCall): string {
|
||||
private async executeTool(call: OllamaToolCall): Promise<string> {
|
||||
switch (call.function.name) {
|
||||
case "get_current_time":
|
||||
return JSON.stringify(this.getCurrentTime());
|
||||
@@ -226,6 +269,20 @@ export class OllamaLlmService {
|
||||
expression: this.getStringArg(call.function.arguments, "expression"),
|
||||
result: this.evaluateMath(this.getStringArg(call.function.arguments, "expression")),
|
||||
});
|
||||
case "web_search":
|
||||
return JSON.stringify(
|
||||
await webSearch(
|
||||
this.getStringArg(call.function.arguments, "query"),
|
||||
Math.min(5, Math.max(1, Math.trunc(this.getNumberArg(call.function.arguments, "max_results", 4)))),
|
||||
),
|
||||
);
|
||||
case "fetch_url":
|
||||
return JSON.stringify(
|
||||
await webFetch(
|
||||
this.getStringArg(call.function.arguments, "url"),
|
||||
Math.min(10000, Math.max(1000, Math.trunc(this.getNumberArg(call.function.arguments, "max_chars", 6000)))),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return JSON.stringify({
|
||||
error: `unknown tool: ${call.function.name}`,
|
||||
@@ -294,4 +351,18 @@ export class OllamaLlmService {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private getNumberArg(args: Record<string, unknown>, name: string, fallback: number): number {
|
||||
const value = args[name];
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
const parsed = Number(value);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user