Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experience Selection [Ready] #406

Merged
merged 13 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ Unlike many agent frameworks that only track the chat history with LLMs in text,


## 🆕 News
- 📅2024-09-13: We introduce the shared memory to store information that is shared between the roles in TaskWeaver. Please check the [memory](https://microsoft.github.io/TaskWeaver/docs/memory) for more details.🧠
- 📅2024-09-13: We have enhanced the experience feature by allowing static and dynamic experience selection. Please check the [experience](https://microsoft.github.io/TaskWeaver/blog/experience) for more details.📚
- 📅2024-07-02: We have optimized TaskWeaver to support not-that-large language models served locally. Please check this [post](https://microsoft.github.io/TaskWeaver/blog/local_llm) for more details.🔗
- 📅2024-05-07: We have added two blog posts on [Evaluating a LLM agent](https://microsoft.github.io/TaskWeaver/blog/evaluation) and [Adding new roles to TaskWeaver](https://microsoft.github.io/TaskWeaver/blog/role) in the documentation.📝
- 📅2024-03-28: TaskWeaver now offers all-in-one Docker image, providing a convenient one-stop experience for users. Please check the [docker](https://microsoft.github.io/TaskWeaver/docs/usage/docker) for more details.🐳
- 📅2024-03-27: TaskWeaver now switches to `container` mode by default for code execution. Please check the [code execution](https://microsoft.github.io/TaskWeaver/docs/code_execution) for more details.🐳
- 📅2024-03-07: TaskWeaver now supports configuration of different LLMs for various components, such as the Planner and CodeInterpreter. Please check the [multi-llm](https://microsoft.github.io/TaskWeaver/docs/llms/multi-llm) for more details.🔗
- 📅2024-03-04: TaskWeaver now supports a [container](https://microsoft.github.io/TaskWeaver/docs/code_execution) mode, which provides a more secure environment for code execution.🐳
- 📅2024-02-28: TaskWeaver now offers a [CLI-only](https://microsoft.github.io/TaskWeaver/docs/advanced/cli_only) mode, enabling users to interact seamlessly with the Command Line Interface (CLI) using natural language.📟
- 📅2024-02-01: TaskWeaver now has a plugin [document_retriever](https://github.com/microsoft/TaskWeaver/blob/main/project/plugins/README.md#document_retriever) for RAG based on a knowledge base.📚
<!-- - 📅2024-02-01: TaskWeaver now has a plugin [document_retriever](https://github.com/microsoft/TaskWeaver/blob/main/project/plugins/README.md#document_retriever) for RAG based on a knowledge base.📚 -->
<!-- - 📅2024-01-30: TaskWeaver introduces a new plugin-only mode that securely generates calls to specified plugins without producing extraneous code.🪡 -->
<!-- - 📅2024-01-23: TaskWeaver can now be personalized by transforming your chat histories into enduring [experiences](https://microsoft.github.io/TaskWeaver/docs/customization/experience) 🎉 -->
<!-- - 📅2024-01-17: TaskWeaver now has a plugin [vision_web_explorer](https://github.com/microsoft/TaskWeaver/blob/main/project/plugins/README.md#vision_web_explorer) that can open a web browser and explore websites.🌐 -->
Expand Down
96 changes: 0 additions & 96 deletions scripts/experience_mgt.py

This file was deleted.

56 changes: 28 additions & 28 deletions taskweaver/code_interpreter/code_interpreter/code_generator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import json
import os
from typing import List, Optional
from typing import List, Optional, Tuple

from injector import inject

Expand Down Expand Up @@ -55,8 +55,6 @@ def _configure(self) -> None:
)
self.auto_plugin_selection_topk = self._get_int("auto_plugin_selection_topk", 3)

self.use_experience = self._get_bool("use_experience", False)

self.llm_alias = self._get_str("llm_alias", default="", required=False)


Expand Down Expand Up @@ -104,14 +102,7 @@ def __init__(
logger.info("Plugin embeddings loaded")
self.selected_plugin_pool = SelectedPluginPool()

if self.config.use_experience:
self.experience_generator = experience_generator
self.experience_generator.refresh()
self.experience_generator.load_experience()
self.logger.info(
"Experience loaded successfully, "
"there are {} experiences".format(len(self.experience_generator.experience_list)),
)
self.experience_generator = experience_generator

self.logger.info("CodeGenerator initialized successfully")

Expand Down Expand Up @@ -166,15 +157,12 @@ def compose_prompt(
self,
rounds: List[Round],
plugins: List[PluginEntry],
selected_experiences: Optional[List[Experience]] = None,
selected_experiences: Optional[List[Tuple[Experience, float]]] = None,
planning_enrichments: Optional[List[str]] = None,
) -> List[ChatMessageType]:
experiences = (
self.experience_generator.format_experience_in_prompt(
self.prompt_data["experience_instruction"],
selected_experiences,
)
if self.config.use_experience
else ""
experiences = self.format_experience(
template=self.prompt_data["experience_instruction"],
experiences=selected_experiences,
)

chat_history = [
Expand Down Expand Up @@ -207,6 +195,7 @@ def compose_prompt(
add_requirements=True,
summary=summary,
plugins=plugins,
planning_enrichments=planning_enrichments,
),
)
return chat_history
Expand All @@ -223,6 +212,7 @@ def compose_conversation(
plugins: List[PluginEntry],
add_requirements: bool = False,
summary: Optional[str] = None,
planning_enrichments: Optional[List[str]] = None,
) -> List[ChatMessageType]:
chat_history: List[ChatMessageType] = []
ignored_types = [
Expand Down Expand Up @@ -260,18 +250,16 @@ def compose_conversation(
user_query = conversation_round.user_query
enrichment = f"The user request is: {user_query}\n\n"

supplementary_info_dict = conversation_round.read_board()
supplementary_info = "\n\n".join([bulletin for bulletin in supplementary_info_dict.values()])
if supplementary_info != "":
enrichment += f"Additional context:\n" f" {supplementary_info}\n\n"
if planning_enrichments:
enrichment += "Additional context:\n" + "\n".join(planning_enrichments) + "\n\n"

user_feedback = "None"
if last_post is not None and last_post.send_from == self.alias:
user_feedback = format_code_feedback(last_post)

user_message += self.user_message_head_template.format(
FEEDBACK=user_feedback,
MESSAGE=f"{enrichment}{post.message}",
MESSAGE=f"{enrichment}The task for this specific step is: {post.message}",
)
elif post.send_from == post.send_to == self.alias:
# for code correction
Expand Down Expand Up @@ -370,12 +358,24 @@ def reply(
if self.config.enable_auto_plugin_selection:
self.plugin_pool = self.select_plugins_for_prompt(query)

if self.config.use_experience:
selected_experiences = self.experience_generator.retrieve_experience(query)
exp_sub_paths = memory.get_shared_memory_entries(entry_type="experience_sub_path")

if exp_sub_paths:
self.tracing.set_span_attribute("experience_sub_path", str(exp_sub_paths))
exp_sub_path = exp_sub_paths[0].content
else:
selected_experiences = None
exp_sub_path = ""
selected_experiences = self.load_experience(query=query, sub_path=exp_sub_path)

planning_enrichments = memory.get_shared_memory_entries(entry_type="plan")

prompt = self.compose_prompt(
rounds,
self.plugin_pool,
selected_experiences,
planning_enrichments=[pe.content for pe in planning_enrichments],
)

prompt = self.compose_prompt(rounds, self.plugin_pool, selected_experiences)
self.tracing.set_span_attribute("prompt", json.dumps(prompt, indent=2))
prompt_size = self.tracing.count_tokens(json.dumps(prompt))
self.tracing.set_span_attribute("prompt_size", prompt_size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ conversation_head: |-

user_message_head: |-
-----------------------------
# Feedback of the code in the last round (None if no feedback):
### Feedback of the code in the last round (None if no feedback):
{FEEDBACK}

# Additional information from the User in this round:
### Request from the User in this round:
{MESSAGE}

requirements: |-
Expand All @@ -96,7 +96,7 @@ requirements: |-
{CODE_GENERATION_REQUIREMENTS}

experience_instruction: |-
## Experience And Lessons
Before generating Python code, please refer to the experiences and lessons learned from the previous tasks:
### Experience And Lessons
Before generating code, please learn from the following past experiences and lessons:
{experiences}
You must use the experiences and lessons learned to generate the Python code.
You must apply them in code generation.
3 changes: 2 additions & 1 deletion taskweaver/config/module_config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import Any, List, Optional

from injector import inject
from injector import inject, singleton

from taskweaver.config.config_mgt import AppConfigSource


@singleton
class ModuleConfig(object):
@inject
def __init__(self, src: AppConfigSource) -> None:
Expand Down
2 changes: 2 additions & 0 deletions taskweaver/memory/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import annotations

from .shared_memory_entry import SharedMemoryEntry
from .attachment import Attachment
from .conversation import Conversation
from .memory import Memory
from .post import Post
from .round import Round
from .compression import RoundCompressor

10 changes: 7 additions & 3 deletions taskweaver/memory/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class AttachmentType(Enum):
invalid_response = "invalid_response"
text = "text"

# board info
board = "board"
# shared memory entry
shared_memory_entry = "shared_memory_entry"


@dataclass
Expand Down Expand Up @@ -95,11 +95,15 @@ def __str__(self) -> str:
return self.__repr__()

def to_dict(self) -> AttachmentDict:
if self.extra is not None and hasattr(self.extra, "to_dict"):
extra_content = self.extra.to_dict()
else:
extra_content = self.extra
return {
"id": self.id,
"type": self.type.value,
"content": self.content,
"extra": self.extra,
"extra": extra_content,
}

@staticmethod
Expand Down
Loading