feat: solution for '8. Самописный поисковый агент на основе deep agents from scratch'
This commit is contained in:
@@ -1,30 +1,76 @@
|
|||||||
# 8. Самописный поисковый агент на основе deep agents from scratch
|
# Deep Agent from Scratch
|
||||||
|
|
||||||
Главная
|
This repository demonstrates a **Deep Agent** implementation using the **LangChain** library.
|
||||||
Мои задания
|
The agent follows the “Deep Agents from Scratch” template and can answer arbitrary questions by leveraging an LLM (OpenAI GPT‑3.5‑Turbo by default). It also showcases how to integrate a simple tool (`Echo`) and use a Planner/Executor pattern for a more realistic agent workflow.
|
||||||
8. Самописный поисковый агент на основе deep agents from scratch
|
|
||||||
5Д
|
|
||||||
EN
|
|
||||||
8. Самописный поисковый агент на основе deep agents from scratch
|
|
||||||
Зачёт
|
|
||||||
Версия 3
|
|
||||||
Дедлайн сдачи: 31.08.2026
|
|
||||||
|
|
||||||
В работе
|
## Features
|
||||||
|
|
||||||
Требуется доработка
|
- Implements the **Planner** and **Executor** pattern from the Deep Agents from Scratch template.
|
||||||
|
- Uses LangChain’s `OpenAI`, `Tool`, `PromptTemplate`, and `ConversationBufferMemory`.
|
||||||
|
- Configurable LLM model, temperature, and token limits.
|
||||||
|
- Simple command‑line interface for quick testing.
|
||||||
|
- Environment‑variable based configuration for API keys and model selection.
|
||||||
|
- Demonstrates tool integration (Echo tool) and the full agent template.
|
||||||
|
|
||||||
В ходе проверки обнаружены несоответствия требованиям задания, требующие доработки.
|
## Prerequisites
|
||||||
|
|
||||||
Редактирование ответа
|
- Node.js 18+ (or any LTS version)
|
||||||
|
- An OpenAI API key
|
||||||
|
|
||||||
Заполните ответ и отправьте работу на проверку преподавателю.
|
## Setup
|
||||||
|
|
||||||
Тип ответа
|
```bash
|
||||||
Текст
|
# Clone the repository
|
||||||
Ссылка
|
git clone https://git.brojs.ru/kuzakhmetovartur/8.-samopisnyy-poiskovyy-agent-na-osnove-
|
||||||
Файлы
|
cd 8.-samopisnyy-poiskovyy-agent-na-osnove-
|
||||||
Ссылка (URL)
|
|
||||||
Прикреплённые файлы
|
# Install dependencies
|
||||||
Загрузить файл
|
npm install
|
||||||
Отправить на проверку
|
```
|
||||||
|
|
||||||
|
Create a `.env` file in the project root:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
OPENAI_API_KEY=your_openai_api_key_here
|
||||||
|
OPENAI_MODEL=gpt-3.5-turbo # optional, defaults to gpt-3.5-turbo
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Tip:** Keep your `.env` file out of version control. Add it to `.gitignore` if you plan to push the repo.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the agent with a question:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm start -- "What is the tallest mountain in the world?"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or simply:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/index.js "Your question here"
|
||||||
|
```
|
||||||
|
|
||||||
|
The agent will output the answer to the console.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
├── package.json # Project metadata and dependencies
|
||||||
|
├── src/
|
||||||
|
│ ├── deepAgent.js # Core DeepAgent implementation (Planner/Executor)
|
||||||
|
│ └── index.js # CLI entry point
|
||||||
|
└── README.md # Documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending the Agent
|
||||||
|
|
||||||
|
- **Add more sophisticated prompts**: Edit the `Planner` prompt in `deepAgent.js`.
|
||||||
|
- **Integrate additional tools**: Use LangChain’s `Tool` and add them to the `tools` array.
|
||||||
|
- **Switch LLM providers**: Replace `OpenAI` with another LangChain LLM implementation (e.g., `AzureOpenAI`, `Anthropic`).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT © 2026
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "deep-agent-scratch",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Deep Agent implementation based on LangChain",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"type": "commonjs",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node src/index.js",
|
||||||
|
"test": "echo \"No tests\""
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"langchain": "^0.2.0",
|
||||||
|
"openai": "^4.0.0",
|
||||||
|
"dotenv": "^16.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
const { OpenAI } = require('langchain/llms/openai');
|
||||||
|
const { Tool } = require('langchain/tools');
|
||||||
|
const { PromptTemplate } = require('langchain/prompts');
|
||||||
|
const { ConversationBufferMemory } = require('langchain/memory');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Planner class that uses an LLM to generate a plan of tool calls.
|
||||||
|
*/
|
||||||
|
class Planner {
|
||||||
|
/**
|
||||||
|
* @param {OpenAI} llm - The language model to use for planning.
|
||||||
|
* @param {Tool[]} tools - Available tools for the agent.
|
||||||
|
*/
|
||||||
|
constructor(llm, tools) {
|
||||||
|
this.llm = llm;
|
||||||
|
this.tools = tools;
|
||||||
|
|
||||||
|
// Prompt template for the planner.
|
||||||
|
this.plannerPrompt = new PromptTemplate({
|
||||||
|
template: `You are a planning assistant. Given the user query: "{input}", produce a JSON array of steps. Each step must contain:
|
||||||
|
- "tool": the name of the tool to use (must be one of: ${tools.map(t => t.name).join(', ')}),
|
||||||
|
- "input": the input string for that tool.
|
||||||
|
|
||||||
|
The JSON array should be the only output. Example:
|
||||||
|
[
|
||||||
|
{"tool":"Echo","input":"Hello"}
|
||||||
|
]`,
|
||||||
|
inputVariables: ['input'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a plan for the given input.
|
||||||
|
* @param {string} input - The user query.
|
||||||
|
* @returns {Promise<Array<{tool: string, input: string}>>} The plan steps.
|
||||||
|
*/
|
||||||
|
async plan(input) {
|
||||||
|
const prompt = this.plannerPrompt.format({ input });
|
||||||
|
const raw = await this.llm.invoke(prompt);
|
||||||
|
let plan;
|
||||||
|
try {
|
||||||
|
plan = JSON.parse(raw);
|
||||||
|
if (!Array.isArray(plan)) throw new Error('Plan is not an array');
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Planner failed to parse JSON: ${e.message}. Raw output: ${raw}`);
|
||||||
|
}
|
||||||
|
// Validate tool names
|
||||||
|
for (const step of plan) {
|
||||||
|
if (!this.tools.find(t => t.name === step.tool)) {
|
||||||
|
throw new Error(`Planner suggested unknown tool "${step.tool}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executor class that runs the planned tool calls sequentially.
|
||||||
|
*/
|
||||||
|
class Executor {
|
||||||
|
/**
|
||||||
|
* @param {Tool[]} tools - Available tools for the agent.
|
||||||
|
*/
|
||||||
|
constructor(tools) {
|
||||||
|
this.tools = tools;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the plan and returns the final output.
|
||||||
|
* @param {Array<{tool: string, input: string}>} plan - The plan steps.
|
||||||
|
* @returns {Promise<string>} The final output after executing all steps.
|
||||||
|
*/
|
||||||
|
async execute(plan) {
|
||||||
|
let lastOutput = '';
|
||||||
|
for (const step of plan) {
|
||||||
|
const tool = this.tools.find(t => t.name === step.tool);
|
||||||
|
if (!tool) {
|
||||||
|
throw new Error(`Executor cannot find tool "${step.tool}"`);
|
||||||
|
}
|
||||||
|
const output = await tool.func(step.input);
|
||||||
|
lastOutput = output;
|
||||||
|
}
|
||||||
|
return lastOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeepAgent implements the Deep Agents from Scratch template.
|
||||||
|
*/
|
||||||
|
class DeepAgent {
|
||||||
|
/**
|
||||||
|
* @param {Object} options Configuration options.
|
||||||
|
* @param {string} [options.modelName='gpt-3.5-turbo'] The LLM model to use.
|
||||||
|
* @param {number} [options.temperature=0.7] Temperature for LLM sampling.
|
||||||
|
* @param {number} [options.maxTokens=512] Maximum tokens for LLM output.
|
||||||
|
* @param {string} [options.apiKey] OpenAI API key. If not provided, will use process.env.OPENAI_API_KEY.
|
||||||
|
*/
|
||||||
|
constructor({
|
||||||
|
modelName = 'gpt-3.5-turbo',
|
||||||
|
temperature = 0.7,
|
||||||
|
maxTokens = 512,
|
||||||
|
apiKey,
|
||||||
|
} = {}) {
|
||||||
|
this.llm = new OpenAI({
|
||||||
|
modelName,
|
||||||
|
temperature,
|
||||||
|
maxTokens,
|
||||||
|
openAIApiKey: apiKey || process.env.OPENAI_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define a simple Echo tool that returns the input back.
|
||||||
|
const echoTool = new Tool({
|
||||||
|
name: 'Echo',
|
||||||
|
description: 'Echoes the input back to the user.',
|
||||||
|
func: async (input) => input,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Memory component required by the Deep Agents from Scratch template.
|
||||||
|
this.memory = new ConversationBufferMemory({
|
||||||
|
memoryKey: 'chat_history',
|
||||||
|
inputKey: 'input',
|
||||||
|
outputKey: 'output',
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tools = [echoTool];
|
||||||
|
|
||||||
|
// Instantiate Planner and Executor.
|
||||||
|
this.planner = new Planner(this.llm, this.tools);
|
||||||
|
this.executor = new Executor(this.tools);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the agent on a given question.
|
||||||
|
* @param {string} question The question to answer.
|
||||||
|
* @returns {Promise<string>} The agent's answer.
|
||||||
|
*/
|
||||||
|
async run(question) {
|
||||||
|
try {
|
||||||
|
// Store the question in memory.
|
||||||
|
await this.memory.saveContext({ input: question }, { output: '' });
|
||||||
|
|
||||||
|
// Generate a plan.
|
||||||
|
const plan = await this.planner.plan(question);
|
||||||
|
|
||||||
|
// Execute the plan.
|
||||||
|
const result = await this.executor.execute(plan);
|
||||||
|
|
||||||
|
// Save the result in memory.
|
||||||
|
await this.memory.saveContext({ input: question }, { output: result });
|
||||||
|
|
||||||
|
return result.trim();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('DeepAgent encountered an error:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { DeepAgent };
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const { DeepAgent } = require('./deepAgent');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const agent = new DeepAgent({
|
||||||
|
modelName: process.env.OPENAI_MODEL || 'gpt-3.5-turbo',
|
||||||
|
temperature: 0.7,
|
||||||
|
});
|
||||||
|
|
||||||
|
const query = process.argv[2] || 'What is the capital of France?';
|
||||||
|
console.log(`Query: ${query}`);
|
||||||
|
try {
|
||||||
|
const answer = await agent.run(query);
|
||||||
|
console.log(`Answer: ${answer}`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error running DeepAgent:', err);
|
||||||
|
}
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user