Skip to content

Commit

Permalink
revise prompt and add task selector to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
leehuwuj committed Oct 3, 2024
1 parent 27a1b9f commit 943ae9b
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 18 deletions.
28 changes: 20 additions & 8 deletions templates/components/multiagent/python/app/examples/workflow.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from textwrap import dedent
from typing import AsyncGenerator, List, Optional
from llama_index.core.settings import Settings
from llama_index.core.prompts import PromptTemplate

from app.agents.single import AgentRunEvent, AgentRunResult, FunctionCallingAgent
from app.examples.publisher import create_publisher
from app.examples.researcher import create_researcher
from llama_index.core.chat_engine.types import ChatMessage
from llama_index.core.prompts import PromptTemplate
from llama_index.core.settings import Settings
from llama_index.core.workflow import (
Context,
Event,
Expand All @@ -33,7 +33,6 @@ def create_workflow(chat_history: Optional[List[ChatMessage]] = None):
You are given the task of writing a blog post based on research content provided by the researcher agent. Do not invent any information yourself.
It's important to read the entire conversation history to write the blog post accurately.
If you receive a review from the reviewer, update the post according to the feedback and return the new post content.
If the user requests an update with new information but no research content is provided, you must respond with: "I don't have any research content to write about."
If the content is not valid (e.g., broken link, broken image, etc.), do not use it.
It's normal for the task to include some ambiguity, so you must define the user's initial request to write the post correctly.
If you update the post based on the reviewer's feedback, first explain what changes you made to the post, then provide the new post content. Do not include the reviewer's comments.
Expand Down Expand Up @@ -128,10 +127,20 @@ async def _decide_workflow(
self, input: str, chat_history: List[ChatMessage]
) -> str:
prompt_template = PromptTemplate(
"Given the following chat history and new task, decide whether to publish based on existing information.\n"
"Chat history:\n{chat_history}\n"
"New task: {input}\n"
"Decision (respond with either 'not_publish' or 'publish'):"
dedent("""
You are an expert in decision-making, helping people write and publish blog posts.
If the user is asking for a file or to publish content, respond with 'publish'.
If the user requests to write or update a blog post, respond with 'not_publish'.
Here is the chat history:
${chat_history}
The current user request is:
${input}
Given the chat history and the new user request, decide whether to publish based on existing information.
Decision (respond with either 'not_publish' or 'publish'):
""")
)

chat_history_str = "\n".join(
Expand Down Expand Up @@ -171,7 +180,10 @@ async def write(
if ev.is_good or too_many_attempts:
# too many attempts or the blog post is good - stream final response if requested
result = await self.run_agent(
ctx, writer, ev.input, streaming=ctx.data["streaming"]
ctx,
writer,
f"Trim the review from the reviewer and return only the blog post content. Here is the content: {ev.input}",
streaming=ctx.data["streaming"],
)
return StopEvent(result=result)
result: AgentRunResult = await self.run_agent(ctx, writer, ev.input)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export const createWriter = (chatHistory: ChatMessage[]) => {
You are given the task of writing a blog post based on research content provided by the researcher agent. Do not invent any information yourself.
It's important to read the entire conversation history to write the blog post accurately.
If you receive a review from the reviewer, update the post according to the feedback and return the new post content.
If the user requests an update with new information but no research content is provided, you must respond with: "I don't have any research content to write about."
If the content is not valid (e.g., broken link, broken image, etc.), do not use it.
It's normal for the task to include some ambiguity, so you must define the user's initial request to write the post correctly.
If you update the post based on the reviewer's feedback, first explain what changes you made to the post, then provide the new post content. Do not include the reviewer's comments.
Expand Down
60 changes: 51 additions & 9 deletions templates/components/multiagent/typescript/workflow/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Workflow,
WorkflowEvent,
} from "@llamaindex/core/workflow";
import { ChatMessage, ChatResponseChunk } from "llamaindex";
import { ChatMessage, ChatResponseChunk, Settings } from "llamaindex";
import {
createPublisher,
createResearcher,
Expand Down Expand Up @@ -82,9 +82,44 @@ export const createWorkflow = (chatHistory: ChatMessage[]) => {

const start = async (context: Context, ev: StartEvent) => {
context.set("task", ev.data.input);
return new ResearchEvent({
input: `Research for this task: ${ev.data.input}`,
});

const chatHistoryStr = chatHistoryWithAgentMessages
.map((msg) => `${msg.role}: ${msg.content}`)
.join("\n");

// Decision-making process
const decision = await decideWorkflow(ev.data.input, chatHistoryStr);

if (decision !== "publish") {
return new ResearchEvent({
input: `Research for this task: ${ev.data.input}`,
});
} else {
return new PublishEvent({
input: `Publish content based on the chat history\n${chatHistoryStr}\n\n and task: ${ev.data.input}`,
});
}
};

const decideWorkflow = async (task: string, chatHistoryStr: string) => {
const llm = Settings.llm;

const prompt = `You are an expert in decision-making, helping people write and publish blog posts.
If the user is asking for a file or to publish content, respond with 'publish'.
If the user requests to write or update a blog post, respond with 'not_publish'.
Here is the chat history:
${chatHistoryStr}
The current user request is:
${task}
Given the chat history and the new user request, decide whether to publish based on existing information.
Decision (respond with either 'not_publish' or 'publish'):`;

const output = await llm.complete({ prompt: prompt });
const decision = output.text.trim().toLowerCase();
return decision === "publish" ? "publish" : "research";
};

const research = async (context: Context, ev: ResearchEvent) => {
Expand All @@ -100,6 +135,8 @@ export const createWorkflow = (chatHistory: ChatMessage[]) => {
};

const write = async (context: Context, ev: WriteEvent) => {
const writer = createWriter(chatHistoryWithAgentMessages);

context.set("attempts", context.get("attempts", 0) + 1);
const tooManyAttempts = context.get("attempts") > MAX_ATTEMPTS;
if (tooManyAttempts) {
Expand All @@ -112,12 +149,15 @@ export const createWorkflow = (chatHistory: ChatMessage[]) => {
}

if (ev.data.isGood || tooManyAttempts) {
return new PublishEvent({
input: "Please help me to publish the blog post.",
// the blog post is good or too many attempts
// stream the final content
const result = await runAgent(context, writer, {
message: `Trim the review from the reviewer and return only the blog post content. Here is the content: ${ev.data.input}`,
streaming: true,
});
return result as unknown as StopEvent<AsyncGenerator<ChatResponseChunk>>;
}

const writer = createWriter(chatHistoryWithAgentMessages);
const writeRes = await runAgent(context, writer, {
message: ev.data.input,
});
Expand Down Expand Up @@ -177,9 +217,11 @@ export const createWorkflow = (chatHistory: ChatMessage[]) => {
};

const workflow = new Workflow({ timeout: TIMEOUT, validate: true });
workflow.addStep(StartEvent, start, { outputs: ResearchEvent });
workflow.addStep(StartEvent, start, {
outputs: [ResearchEvent, PublishEvent],
});
workflow.addStep(ResearchEvent, research, { outputs: WriteEvent });
workflow.addStep(WriteEvent, write, { outputs: [ReviewEvent, PublishEvent] });
workflow.addStep(WriteEvent, write, { outputs: [ReviewEvent, StopEvent] });
workflow.addStep(ReviewEvent, review, { outputs: WriteEvent });
workflow.addStep(PublishEvent, publish, { outputs: StopEvent });

Expand Down

0 comments on commit 943ae9b

Please sign in to comment.