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
|
||||
|
||||
Главная
|
||||
Мои задания
|
||||
8. Самописный поисковый агент на основе deep agents from scratch
|
||||
5Д
|
||||
EN
|
||||
8. Самописный поисковый агент на основе deep agents from scratch
|
||||
Зачёт
|
||||
Версия 3
|
||||
Дедлайн сдачи: 31.08.2026
|
||||
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.
|
||||
|
||||
В работе
|
||||
## 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
|
||||
|
||||
Тип ответа
|
||||
Текст
|
||||
Ссылка
|
||||
Файлы
|
||||
Ссылка (URL)
|
||||
Прикреплённые файлы
|
||||
Загрузить файл
|
||||
Отправить на проверку
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://git.brojs.ru/kuzakhmetovartur/8.-samopisnyy-poiskovyy-agent-na-osnove-
|
||||
cd 8.-samopisnyy-poiskovyy-agent-na-osnove-
|
||||
|
||||
# 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